GCC Code Coverage Report


Directory: ./
File: sql/binlog.cc
Date: 2022-11-26 14:12:44
Exec Total Coverage
Lines: 4179 4572 91.4%
Branches: 5181 9325 55.6%

Line Branch Exec Source
1 /* Copyright (c) 2009, 2022, Oracle and/or its affiliates.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License, version 2.0,
5 as published by the Free Software Foundation.
6
7 This program is also distributed with certain software (including
8 but not limited to OpenSSL) that is licensed under separate terms,
9 as designated in a particular file or component or in included license
10 documentation. The authors of MySQL hereby grant you an additional
11 permission to link the program and your derivative works with the
12 separately licensed software that they have included with MySQL.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License, version 2.0, for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
22
23 #include "sql/binlog.h"
24
25 #include "my_config.h"
26
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <limits.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <time.h>
33
34 #include "lex_string.h"
35 #include "map_helpers.h"
36 #include "my_alloc.h"
37 #include "my_loglevel.h"
38 #include "my_macros.h"
39 #include "my_systime.h"
40 #include "my_thread.h"
41 #include "sql/check_stack.h"
42 #include "sql/clone_handler.h"
43 #include "sql_string.h"
44 #include "template_utils.h"
45 #ifdef HAVE_UNISTD_H
46 #include <unistd.h>
47 #endif
48 #include <algorithm>
49 #include <list>
50 #include <map>
51 #include <new>
52 #include <queue>
53 #include <sstream>
54 #include <string>
55
56 #include "dur_prop.h"
57 #include "libbinlogevents/include/compression/base.h"
58 #include "libbinlogevents/include/compression/iterator.h"
59 #include "libbinlogevents/include/control_events.h"
60 #include "libbinlogevents/include/debug_vars.h"
61 #include "libbinlogevents/include/rows_event.h"
62 #include "libbinlogevents/include/statement_events.h"
63 #include "libbinlogevents/include/table_id.h"
64 #include "mf_wcomp.h" // wild_one, wild_many
65 #include "mutex_lock.h" // Mutex_lock
66 #include "my_base.h"
67 #include "my_bitmap.h"
68 #include "my_byteorder.h"
69 #include "my_compiler.h"
70 #include "my_dbug.h"
71 #include "my_dir.h"
72 #include "my_sqlcommand.h"
73 #include "my_stacktrace.h" // my_safe_print_system_time
74 #include "my_thread_local.h"
75 #include "mysql/components/services/log_builtins.h"
76 #include "mysql/plugin.h"
77 #include "mysql/psi/mysql_file.h"
78 #include "mysql/service_mysql_alloc.h"
79 #include "mysql/thread_type.h"
80 #include "mysqld_error.h"
81 #include "partition_info.h"
82 #include "prealloced_array.h"
83 #include "sql/binlog/global.h"
84 #include "sql/binlog/recovery.h" // binlog::Binlog_recovery
85 #include "sql/binlog/tools/iterators.h"
86 #include "sql/binlog_ostream.h"
87 #include "sql/binlog_reader.h"
88 #include "sql/create_field.h"
89 #include "sql/current_thd.h"
90 #include "sql/debug_sync.h" // DEBUG_SYNC
91 #include "sql/derror.h" // ER_THD
92 #include "sql/discrete_interval.h"
93 #include "sql/field.h"
94 #include "sql/handler.h"
95 #include "sql/item_func.h" // user_var_entry
96 #include "sql/key.h"
97 #include "sql/log.h"
98 #include "sql/log_event.h" // Rows_log_event
99 #include "sql/mysqld.h" // sync_binlog_period ...
100 #include "sql/mysqld_thd_manager.h" // Global_THD_manager
101 #include "sql/protocol.h"
102 #include "sql/psi_memory_key.h"
103 #include "sql/query_options.h"
104 #include "sql/raii/sentry.h" // raii::Sentry<>
105 #include "sql/rpl_filter.h"
106 #include "sql/rpl_gtid.h"
107 #include "sql/rpl_handler.h" // RUN_HOOK
108 #include "sql/rpl_mi.h" // Master_info
109 #include "sql/rpl_record.h"
110 #include "sql/rpl_replica.h"
111 #include "sql/rpl_replica_commit_order_manager.h" // Commit_order_manager
112 #include "sql/rpl_rli.h" // Relay_log_info
113 #include "sql/rpl_rli_pdb.h" // Slave_worker
114 #include "sql/rpl_transaction_ctx.h"
115 #include "sql/rpl_trx_boundary_parser.h" // Transaction_boundary_parser
116 #include "sql/rpl_utility.h"
117 #include "sql/sql_backup_lock.h" // is_instance_backup_locked
118 #include "sql/sql_base.h" // find_temporary_table
119 #include "sql/sql_bitmap.h"
120 #include "sql/sql_class.h" // THD
121 #include "sql/sql_const.h"
122 #include "sql/sql_data_change.h"
123 #include "sql/sql_error.h"
124 #include "sql/sql_lex.h"
125 #include "sql/sql_list.h"
126 #include "sql/sql_parse.h" // sqlcom_can_generate_row_events
127 #include "sql/sql_show.h" // append_identifier
128 #include "sql/system_variables.h"
129 #include "sql/table.h"
130 #include "sql/transaction_info.h"
131 #include "sql/xa.h"
132 #include "sql/xa/sql_cmd_xa.h" // Sql_cmd_xa_*
133 #include "sql_partition.h"
134 #include "thr_lock.h"
135
136 class Item;
137
138 using binary_log::checksum_crc32;
139 using std::list;
140 using std::max;
141 using std::min;
142 using std::string;
143
144 #define FLAGSTR(V, F) ((V) & (F) ? #F " " : "")
145 #define YESNO(X) ((X) ? "yes" : "no")
146
147 /**
148 @defgroup Binary_Log Binary Log
149 @{
150 */
151
152 #define MY_OFF_T_UNDEF (~(my_off_t)0UL)
153
154 /*
155 Constants required for the limit unsafe warnings suppression
156 */
157 // seconds after which the limit unsafe warnings suppression will be activated
158 #define LIMIT_UNSAFE_WARNING_ACTIVATION_TIMEOUT 50
159 // number of limit unsafe warnings after which the suppression will be activated
160 #define LIMIT_UNSAFE_WARNING_ACTIVATION_THRESHOLD_COUNT 50
161
162 static ulonglong limit_unsafe_suppression_start_time = 0;
163 static bool unsafe_warning_suppression_is_activated = false;
164 static int limit_unsafe_warning_count = 0;
165
166 static handlerton *binlog_hton;
167 bool opt_binlog_order_commits = true;
168
169 const char *log_bin_index = nullptr;
170 const char *log_bin_basename = nullptr;
171
172 /* Size for IO_CACHE buffer for binlog & relay log */
173 ulong rpl_read_size;
174
175 MYSQL_BIN_LOG mysql_bin_log(&sync_binlog_period);
176
177 static int binlog_init(void *p);
178 static int binlog_start_trans_and_stmt(THD *thd, Log_event *start_event);
179 static int binlog_close_connection(handlerton *hton, THD *thd);
180 static int binlog_savepoint_set(handlerton *hton, THD *thd, void *sv);
181 static int binlog_savepoint_rollback(handlerton *hton, THD *thd, void *sv);
182 static bool binlog_savepoint_rollback_can_release_mdl(handlerton *hton,
183 THD *thd);
184 static int binlog_commit(handlerton *hton, THD *thd, bool all);
185 static int binlog_rollback(handlerton *hton, THD *thd, bool all);
186 /*
187 This function is used to prepare a transaction. For the binary log SE.
188
189 @param hton The pointer to the binlog SE plugin.
190 @param thd The THD session object holding the transaction to be prepared.
191 @param all Preparing a transaction (i.e. true) or a statement
192 (i.e. false).
193
194 @return 0 if the function is successfully executed, non-zero otherwise
195 */
196 static int binlog_prepare(handlerton *hton, THD *thd, bool all);
197 /*
198 This function is used to mark an X/Open XA distributed transaction as
199 being prepared in the server transaction coordinator.
200
201 Is a no-op function, added to the handler API to workaround warnings that
202 are triggered for SEs participating in a transaction that requires this
203 callback but such callback is not available.
204
205 @param hton The pointer to the binlog SE plugin.
206 @param thd The THD session object holding the transaction to be updated.
207
208 @return 0 if the function is successfully executed, non-zero otherwise
209 */
210 static int binlog_set_prepared_in_tc(handlerton *hton, THD *thd);
211 static void exec_binlog_error_action_abort(const char *err_string);
212 static void binlog_prepare_row_images(const THD *thd, TABLE *table);
213 static bool is_loggable_xa_prepare(THD *thd);
214 static int check_instance_backup_locked();
215
216 namespace {
217 /**
218 Finishes the transaction in the engines. If the `commit_low` flag is set,
219 will commit in the engines, otherwise, if the underlying statement is an
220 `XA ROLLBACK`, it will rollback in the engines.
221
222 @param thd The THD session object holding the transaction to finalize.
223 @param all Finalizing a transaction (i.e. true) or a statement
224 (i.e. false).
225 @param run_after_commit In the case of a commit being issued, whether or
226 not to run the `after_commit` hook.
227 */
228 void finish_transaction_in_engines(THD *thd, bool all, bool run_after_commit);
229 } // namespace
230
231 2969763 bool normalize_binlog_name(char *to, const char *from, bool is_relay_log) {
232
1/2
✓ Branch 0 taken 2969763 times.
✗ Branch 1 not taken.
2969763 DBUG_TRACE;
233 2969763 bool error = false;
234 char buff[FN_REFLEN];
235 2969763 char *ptr = const_cast<char *>(from);
236
2/2
✓ Branch 0 taken 2484370 times.
✓ Branch 1 taken 485393 times.
2969763 char *opt_name = is_relay_log ? opt_relay_logname : opt_bin_logname;
237
238
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2969763 times.
2969763 assert(from);
239
240 /* opt_name is not null and not empty and from is a relative path */
241
8/12
✓ Branch 0 taken 2969763 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2969763 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2969763 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2969763 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2969573 times.
✓ Branch 9 taken 190 times.
✓ Branch 10 taken 2969573 times.
✓ Branch 11 taken 190 times.
2969763 if (opt_name && opt_name[0] && from && !test_if_hard_path(from)) {
242 // take the path from opt_name
243 // take the filename from from
244 char log_dirpart[FN_REFLEN], log_dirname[FN_REFLEN];
245 size_t log_dirpart_len, log_dirname_len;
246
1/2
✓ Branch 0 taken 2969573 times.
✗ Branch 1 not taken.
2969573 dirname_part(log_dirpart, opt_name, &log_dirpart_len);
247
1/2
✓ Branch 0 taken 2969573 times.
✗ Branch 1 not taken.
2969573 dirname_part(log_dirname, from, &log_dirname_len);
248
249 /* log may be empty => relay-log or log-bin did not
250 hold paths, just filename pattern */
251
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 2969519 times.
2969573 if (log_dirpart_len > 0) {
252 /* create the new path name */
253
1/2
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
54 if (fn_format(buff, from + log_dirname_len, log_dirpart, "",
254
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 54 times.
54 MYF(MY_UNPACK_FILENAME | MY_SAFE_PATH)) == nullptr) {
255 error = true;
256 goto end;
257 }
258
259 54 ptr = buff;
260 }
261 }
262
263
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2969763 times.
2969763 assert(ptr);
264
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2969763 times.
2969763 if (ptr) {
265 2969763 size_t length = strlen(ptr);
266
267 // Strips the CR+LF at the end of log name and \0-terminates it.
268
3/4
✓ Branch 0 taken 2969763 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2874514 times.
✓ Branch 3 taken 95249 times.
2969763 if (length && ptr[length - 1] == '\n') {
269 2874514 ptr[length - 1] = 0;
270 2874514 length--;
271
2/4
✓ Branch 0 taken 2874514 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2874514 times.
2874514 if (length && ptr[length - 1] == '\r') {
272 ptr[length - 1] = 0;
273 length--;
274 }
275 }
276
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2969763 times.
2969763 if (!length) {
277 error = true;
278 goto end;
279 }
280
1/2
✓ Branch 0 taken 2969763 times.
✗ Branch 1 not taken.
2969763 strmake(to, ptr, length);
281 }
282 end:
283 2969763 return error;
284 2969763 }
285
286 static int binlog_start_consistent_snapshot(handlerton *hton, THD *thd);
287 static int binlog_clone_consistent_snapshot(handlerton *hton, THD *thd,
288 THD *from_thd);
289
290 ulonglong binlog_space_limit;
291
292 // The last published global binlog position
293 static char binlog_global_snapshot_file[FN_REFLEN];
294 static ulonglong binlog_global_snapshot_position;
295
296 // Binlog position variables for SHOW STATUS
297 static char binlog_snapshot_file[FN_REFLEN];
298 static ulonglong binlog_snapshot_position;
299 static std::string binlog_snapshot_gtid_executed;
300
301 static SHOW_VAR binlog_status_vars_detail[] = {
302 {"snapshot_file", (char *)&binlog_snapshot_file, SHOW_CHAR,
303 SHOW_SCOPE_GLOBAL},
304 {"snapshot_position", (char *)&binlog_snapshot_position, SHOW_LONGLONG,
305 SHOW_SCOPE_GLOBAL},
306 {NullS, NullS, SHOW_LONG, SHOW_SCOPE_GLOBAL}};
307
308 /**
309 @brief Checks whether purge conditions are met to be able to run purge
310 for binary log files.
311
312 This function checks whether the binary log is open, if the instance
313 is not locked for backup.
314
315 @param log The reference to the binary log.
316 @return std::pair<bool, int> the first element states whether there is a
317 purge condition violation. The second element states what is the associated
318 error code, if any.
319 */
320 8837 static std::pair<bool, int> check_purge_conditions(const MYSQL_BIN_LOG &log) {
321 // is the binary log open?
322
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 8835 times.
8837 if (!log.is_open()) {
323
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 return std::make_pair(true, 0);
324 }
325
326 // is instance locked for backup ?
327 8835 int error{0};
328
3/4
✓ Branch 0 taken 8835 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 31 times.
✓ Branch 3 taken 8804 times.
8835 if ((error = check_instance_backup_locked()) != 0) {
329
1/2
✓ Branch 0 taken 31 times.
✗ Branch 1 not taken.
31 return std::make_pair(true, error);
330 }
331
332 // go ahead, validations checked successfully
333
1/2
✓ Branch 0 taken 8804 times.
✗ Branch 1 not taken.
8804 return std::make_pair(false, 0);
334 }
335
336 /**
337 @brief This function abstracts the calculation of the binary log files
338 retention lower bound. It is just a function that makes it easier
339 to handle the fact that there are two mutually exclusive variables
340 that control the purge period and one of them is deprecated.
341
342 NOTE: This function and part of the purge validation functions should
343 really move to a retention policy class that abstracts the
344 retention policy altogether and its controls. Perhaps we
345 can do that once expire_logs_days is removed and a refactoring
346 is done to also include retention based on storage space
347 occupied. Then we can uses the same retention abstraction
348 for binary and relay logs and possibly extend the options
349 to retain (binary) log files not only based on time, but
350 also on space used.
351
352 @return time_t the time after which log files are considered expired.
353 */
354 39760 static time_t calculate_auto_purge_lower_time_bound() {
355
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39760 times.
39760 if (DBUG_EVALUATE_IF("expire_logs_always", true, false)) return time(nullptr);
356
357
2/2
✓ Branch 0 taken 39724 times.
✓ Branch 1 taken 36 times.
39760 if (binlog_expire_logs_seconds > 0)
358 39724 return time(nullptr) - binlog_expire_logs_seconds;
359
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 else if (expire_logs_days > 0)
360 36 return time(nullptr) -
361 36 expire_logs_days * static_cast<time_t>(SECONDS_IN_24H);
362
363 // This function should only be called if binlog_expire_logs_seconds
364 // or expire_logs_days are greater than 0. In debug builds assert.
365 // In the event that on production builds there is ever a bug,
366 // that causes the caller to call this function with expire time set
367 // to 0, then do not purge - return 0 and thus file stat time is
368 // always greater than purge time.
369 assert(false); /* purecov: inspected */
370 return 0; /* purecov: inspected */
371 }
372
373 /**
374 @brief Checks if automatic purge conditions are met and therefore the
375 purge is allowed to be done. If not met returns true. Otherwise, false.
376
377 @return false if the check is successful. True otherwise.
378 */
379 19924 static bool check_auto_purge_conditions() {
380 // purge is disabled
381
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 19915 times.
19924 if (!opt_binlog_expire_logs_auto_purge) return true;
382
383 // no retention window configured
384
4/4
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 19878 times.
✓ Branch 2 taken 19 times.
✓ Branch 3 taken 18 times.
19915 if (binlog_expire_logs_seconds == 0 && expire_logs_days == 0) return true;
385
386 // retention window is set, but we are still within the window
387
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 19895 times.
19896 if (calculate_auto_purge_lower_time_bound() < 0) return true;
388
389 // go ahead, validations checked successfully
390 19895 return false;
391 }
392
393 /**
394 Logical binlog file which wraps and hides the detail of lower layer storage
395 implementation. Binlog code just use this class to control real storage
396 */
397 class MYSQL_BIN_LOG::Binlog_ofile : public Basic_ostream {
398 public:
399 541960 ~Binlog_ofile() override {
400 270980 DBUG_TRACE;
401 270980 close();
402 270980 return;
403 541960 }
404
405 /**
406 Opens the binlog file. It opens the lower layer storage.
407
408 @param[in] log_file_key The PSI_file_key for this stream
409 @param[in] binlog_name The file to be opened
410 @param[in] flags The flags used by IO_CACHE.
411 @param[in] existing True if opening the file, false if creating a new one.
412
413 @retval false Success
414 @retval true Error
415 */
416 87303 bool open(
417 #ifdef HAVE_PSI_INTERFACE
418 PSI_file_key log_file_key,
419 #endif
420 const char *binlog_name, myf flags, bool existing = false) {
421
1/2
✓ Branch 0 taken 87303 times.
✗ Branch 1 not taken.
87303 DBUG_TRACE;
422
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 87303 times.
87303 assert(m_pipeline_head == nullptr);
423
424 #ifndef NDEBUG
425 {
426 #ifndef HAVE_PSI_INTERFACE
427 PSI_file_key log_file_key = PSI_NOT_INSTRUMENTED;
428 #endif
429 MY_STAT info;
430
3/4
✓ Branch 0 taken 87303 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 84431 times.
✓ Branch 3 taken 2872 times.
87303 if (!mysql_file_stat(log_file_key, binlog_name, &info, MYF(0))) {
431
2/4
✓ Branch 0 taken 84431 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 84431 times.
84431 assert(existing == !(my_errno() == ENOENT));
432
1/2
✓ Branch 0 taken 84431 times.
✗ Branch 1 not taken.
84431 set_my_errno(0);
433 }
434 }
435 #endif
436
437
2/4
✓ Branch 0 taken 87303 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 87303 times.
✗ Branch 3 not taken.
87303 std::unique_ptr<IO_CACHE_ostream> file_ostream(new IO_CACHE_ostream);
438
2/4
✓ Branch 0 taken 87303 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 87303 times.
87303 if (file_ostream->open(log_file_key, binlog_name, flags)) return true;
439
440 87303 m_pipeline_head = std::move(file_ostream);
441
442 /* Setup encryption for new files if needed */
443
7/8
✓ Branch 0 taken 84431 times.
✓ Branch 1 taken 2872 times.
✓ Branch 2 taken 84431 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 277 times.
✓ Branch 5 taken 84154 times.
✓ Branch 6 taken 277 times.
✓ Branch 7 taken 87026 times.
87303 if (!existing && rpl_encryption.is_enabled()) {
444 std::unique_ptr<Binlog_encryption_ostream> encrypted_ostream(
445
1/2
✓ Branch 0 taken 277 times.
✗ Branch 1 not taken.
277 new Binlog_encryption_ostream());
446
2/4
✓ Branch 0 taken 277 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 277 times.
277 if (encrypted_ostream->open(std::move(m_pipeline_head))) return true;
447
1/2
✓ Branch 0 taken 277 times.
✗ Branch 1 not taken.
277 m_encrypted_header_size = encrypted_ostream->get_header_size();
448 277 m_pipeline_head = std::move(encrypted_ostream);
449
1/2
✓ Branch 0 taken 277 times.
✗ Branch 1 not taken.
277 }
450
451 87303 return false;
452 87303 }
453
454 /**
455 Opens an existing binlog file. It opens the lower layer storage reusing the
456 existing file password if needed.
457
458 @param[in] log_file_key The PSI_file_key for this stream
459 @param[in] binlog_name The file to be opened
460 @param[in] flags The flags used by IO_CACHE.
461
462 @retval std::unique_ptr A Binlog_ofile object pointer.
463 @retval nullptr Error.
464 */
465 2873 static std::unique_ptr<Binlog_ofile> open_existing(
466 #ifdef HAVE_PSI_INTERFACE
467 PSI_file_key log_file_key,
468 #endif
469 const char *binlog_name, myf flags) {
470
1/2
✓ Branch 0 taken 2873 times.
✗ Branch 1 not taken.
2873 DBUG_TRACE;
471 2873 std::unique_ptr<Rpl_encryption_header> header;
472 unsigned char magic[BINLOG_MAGIC_SIZE];
473
474 /* Open a simple istream to read the magic from the file */
475
1/2
✓ Branch 0 taken 2873 times.
✗ Branch 1 not taken.
2873 IO_CACHE_istream istream;
476
3/4
✓ Branch 0 taken 2873 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 2872 times.
2873 if (istream.open(key_file_binlog, key_file_binlog_cache, binlog_name,
477 MYF(MY_WME | MY_DONT_CHECK_FILESIZE), rpl_read_size))
478 1 return nullptr;
479
2/4
✓ Branch 0 taken 2872 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2872 times.
2872 if (istream.read(magic, BINLOG_MAGIC_SIZE) != BINLOG_MAGIC_SIZE)
480 return nullptr;
481
482 assert(Rpl_encryption_header::ENCRYPTION_MAGIC_SIZE == BINLOG_MAGIC_SIZE);
483 /* Identify the file type by the magic to get the encryption header */
484
2/2
✓ Branch 0 taken 1092 times.
✓ Branch 1 taken 1780 times.
2872 if (memcmp(magic, Rpl_encryption_header::ENCRYPTION_MAGIC,
485 BINLOG_MAGIC_SIZE) == 0) {
486
1/2
✓ Branch 0 taken 1092 times.
✗ Branch 1 not taken.
1092 header = Rpl_encryption_header::get_header(&istream);
487
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1092 times.
1092 if (header == nullptr) return nullptr;
488
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1780 times.
1780 } else if (memcmp(magic, BINLOG_MAGIC, BINLOG_MAGIC_SIZE) != 0) {
489 return nullptr;
490 }
491
492 /* Open the binlog_ofile */
493
1/2
✓ Branch 0 taken 2872 times.
✗ Branch 1 not taken.
2872 std::unique_ptr<Binlog_ofile> ret_ofile(new Binlog_ofile);
494
2/4
✓ Branch 0 taken 2872 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2872 times.
2872 if (ret_ofile->open(
495 #ifdef HAVE_PSI_INTERFACE
496 log_file_key,
497 #endif
498 binlog_name, flags, true)) {
499 return nullptr;
500 }
501
502
2/2
✓ Branch 0 taken 1092 times.
✓ Branch 1 taken 1780 times.
2872 if (header != nullptr) {
503 /* Add the encryption stream on top of IO_CACHE */
504 std::unique_ptr<Binlog_encryption_ostream> encrypted_ostream(
505
1/2
✓ Branch 0 taken 1092 times.
✗ Branch 1 not taken.
1092 new Binlog_encryption_ostream);
506
1/2
✓ Branch 0 taken 1092 times.
✗ Branch 1 not taken.
1092 ret_ofile->m_encrypted_header_size = header->get_header_size();
507
1/2
✓ Branch 0 taken 1092 times.
✗ Branch 1 not taken.
2184 encrypted_ostream->open(std::move(ret_ofile->m_pipeline_head),
508 1092 std::move(header));
509 1092 ret_ofile->m_pipeline_head = std::move(encrypted_ostream);
510 1092 ret_ofile->set_encrypted();
511 1092 }
512 2872 return ret_ofile;
513 2873 }
514
515 218045 void close() {
516 218045 m_pipeline_head.reset(nullptr);
517 218045 m_position = 0;
518 218045 m_encrypted_header_size = 0;
519 218045 }
520
521 /**
522 Writes data into storage and maintains binlog position.
523
524 @param[in] buffer the data will be written
525 @param[in] length the length of the data
526
527 @retval false Success
528 @retval true Error
529 */
530 171008477 bool write(const unsigned char *buffer, my_off_t length) override {
531
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 171008459 times.
171008477 assert(m_pipeline_head != nullptr);
532
533
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 171008430 times.
171008459 if (m_pipeline_head->write(buffer, length)) return true;
534
535 171008430 m_position += length;
536 171008430 return false;
537 }
538
539 /**
540 Updates some bytes in the binlog file. If is only used for clearing
541 LOG_EVENT_BINLOG_IN_USE_F.
542
543 @param[in] buffer the data will be written
544 @param[in] length the length of the data
545 @param[in] offset the offset of the bytes will be updated
546
547 @retval false Success
548 @retval true Error
549 */
550 30873 bool update(const unsigned char *buffer, my_off_t length, my_off_t offset) {
551
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30873 times.
30873 assert(m_pipeline_head != nullptr);
552
1/2
✓ Branch 0 taken 30873 times.
✗ Branch 1 not taken.
61746 return m_pipeline_head->seek(offset) ||
553
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30873 times.
61746 m_pipeline_head->write(buffer, length);
554 }
555
556 /**
557 Truncates some data at the end of the binlog file.
558
559 @param[in] offset where the binlog file will be truncated to.
560
561 @retval false Success
562 @retval true Error
563 */
564 12 bool truncate(my_off_t offset) {
565
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 assert(m_pipeline_head != nullptr);
566
567
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (m_pipeline_head->truncate(offset)) return true;
568 12 m_position = offset;
569 12 return false;
570 }
571
572 7842381 bool flush() { return m_pipeline_head->flush(); }
573 5915369 bool sync() { return m_pipeline_head->sync(); }
574
3/4
✓ Branch 0 taken 166984 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 166984 times.
166986 bool flush_and_sync() { return flush() || sync(); }
575 33401973 my_off_t position() { return m_position; }
576 84431 bool is_empty() { return position() == 0; }
577 5783725 bool is_open() { return m_pipeline_head != nullptr; }
578 /**
579 Returns the encrypted header size of the binary log file.
580
581 @retval 0 The file is not encrypted.
582 @retval >0 The encryption header size.
583 */
584 1692343 int get_encrypted_header_size() { return m_encrypted_header_size; }
585 /**
586 Returns the real file size.
587
588 While position() returns the "file size" from the plain binary log events
589 stream point of view, this function considers the encryption header when it
590 exists.
591
592 @return The real file size considering the encryption header.
593 */
594 7974060 my_off_t get_real_file_size() { return m_position + m_encrypted_header_size; }
595 /**
596 Get the pipeline head.
597
598 @retval Returns the pipeline head or nullptr.
599 */
600 1070 std::unique_ptr<Truncatable_ostream> get_pipeline_head() {
601 1070 return std::move(m_pipeline_head);
602 }
603 /**
604 Check if the log file is encrypted.
605
606 @retval True if the log file is encrypted.
607 @retval False if the log file is not encrypted.
608 */
609 1158 bool is_encrypted() { return m_encrypted; }
610 /**
611 Set that the log file is encrypted.
612 */
613 1092 void set_encrypted() { m_encrypted = true; }
614
615 private:
616 my_off_t m_position = 0;
617 int m_encrypted_header_size = 0;
618 std::unique_ptr<Truncatable_ostream> m_pipeline_head;
619 bool m_encrypted = false;
620 };
621
622 /**
623 Helper class to switch to a new thread and then go back to the previous one,
624 when the object is destroyed using RAII.
625
626 This class is used to temporarily switch to another session (THD
627 structure). It will set up thread specific "globals" correctly
628 so that the POSIX thread looks exactly like the session attached to.
629 However, PSI_thread info is not touched as it is required to show
630 the actual physical view in PFS instrumentation i.e., it should
631 depict as the real thread doing the work instead of thread it switched
632 to.
633
634 On destruction, the original session (which is supplied to the
635 constructor) will be re-attached automatically. For example, with
636 this code, the value of @c current_thd will be the same before and
637 after execution of the code.
638
639 @code
640 {
641 for (int i = 0 ; i < count ; ++i)
642 {
643 // here we are attached to current_thd
644 // [...]
645 Thd_backup_and_restore switch_thd(current_thd, other_thd[i]);
646 // [...]
647 // here we are attached to other_thd[i]
648 // [...]
649 }
650 // here we are attached to current_thd
651 }
652 @endcode
653
654 @warning The class is not designed to be inherited from.
655 */
656
657 class Thd_backup_and_restore {
658 public:
659 /**
660 Try to attach the POSIX thread to a session.
661
662 @param[in] backup_thd The thd to restore to when object is destructed.
663 @param[in] new_thd The thd to attach to.
664 */
665
666 23701490 Thd_backup_and_restore(THD *backup_thd, THD *new_thd)
667 23701490 : m_backup_thd(backup_thd),
668 23701490 m_new_thd(new_thd),
669 23701490 m_new_thd_old_real_id(new_thd->real_id),
670 23701490 m_new_thd_old_thread_stack(new_thd->thread_stack) {
671
2/4
✓ Branch 0 taken 23701507 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23701507 times.
✗ Branch 3 not taken.
23701490 assert(m_backup_thd != nullptr && m_new_thd != nullptr);
672 // Reset the state of the current thd.
673 23701507 m_backup_thd->restore_globals();
674
675 23701502 m_new_thd->thread_stack = m_backup_thd->thread_stack;
676 23701502 m_new_thd->store_globals();
677 #ifdef HAVE_PSI_THREAD_INTERFACE
678 23701475 PSI_THREAD_CALL(set_mem_cnt_THD)(m_new_thd, &m_backup_cnt_thd);
679 #endif
680 23701474 }
681
682 /**
683 Restores to previous thd.
684 */
685 23701506 ~Thd_backup_and_restore() {
686 /*
687 Restore the global variables of the thd we previously attached to,
688 to its original state. In other words, detach the m_new_thd.
689 */
690 23701506 m_new_thd->restore_globals();
691 23701520 m_new_thd->real_id = m_new_thd_old_real_id;
692 23701520 m_new_thd->thread_stack = m_new_thd_old_thread_stack;
693
694 // Reset the global variables to the original state.
695 23701520 m_backup_thd->store_globals();
696 #ifdef HAVE_PSI_THREAD_INTERFACE
697 23701509 PSI_THREAD_CALL(set_mem_cnt_THD)(m_backup_cnt_thd, &m_dummy_cnt_thd);
698 #endif
699 23701504 }
700
701 private:
702 THD *m_backup_thd;
703 THD *m_new_thd;
704 THD *m_backup_cnt_thd;
705 THD *m_dummy_cnt_thd;
706 my_thread_t m_new_thd_old_real_id;
707 const char *m_new_thd_old_thread_stack;
708 };
709
710 /**
711 Caches for non-transactional and transactional data before writing
712 it to the binary log.
713
714 @todo All the access functions for the flags suggest that the
715 encapsuling is not done correctly, so try to move any logic that
716 requires access to the flags into the cache.
717 */
718 class binlog_cache_data {
719 public:
720 93347 binlog_cache_data(bool trx_cache_arg, ulong *ptr_binlog_cache_use_arg,
721 ulong *ptr_binlog_cache_disk_use_arg)
722 186697 : m_pending(nullptr),
723 93350 ptr_binlog_cache_use(ptr_binlog_cache_use_arg),
724
1/2
✓ Branch 0 taken 93350 times.
✗ Branch 1 not taken.
93347 ptr_binlog_cache_disk_use(ptr_binlog_cache_disk_use_arg) {
725 93350 flags.transactional = trx_cache_arg;
726 93350 }
727
728 93350 bool open(my_off_t cache_size, my_off_t max_cache_size) {
729 93350 return m_cache.open(cache_size, max_cache_size);
730 }
731
732 6134600 Binlog_cache_storage *get_cache() { return &m_cache; }
733 int finalize(THD *thd, Log_event *end_event);
734 int finalize(THD *thd, Log_event *end_event, XID_STATE *xs);
735 int flush(THD *thd, my_off_t *bytes, bool *wrote_xid);
736 int write_event(Log_event *event);
737 5927166 size_t get_event_counter() { return event_counter; }
738 5927057 size_t get_compressed_size() { return m_compressed_size; }
739 5927057 size_t get_decompressed_size() { return m_decompressed_size; }
740 5927057 binary_log::transaction::compression::type get_compression_type() {
741 5927057 return m_compression_type;
742 }
743
744 5927312 void set_compressed_size(size_t s) { m_compressed_size = s; }
745 5927460 void set_decompressed_size(size_t s) { m_decompressed_size = s; }
746 5927309 void set_compression_type(binary_log::transaction::compression::type t) {
747 5927309 m_compression_type = t;
748 5927309 }
749
750 180760 virtual ~binlog_cache_data() {
751
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 90389 times.
180760 assert(is_binlog_empty());
752 180778 m_cache.close();
753 }
754
755 102744958 bool is_binlog_empty() const {
756
4/4
✓ Branch 0 taken 2927 times.
✓ Branch 1 taken 102743414 times.
✓ Branch 2 taken 1662 times.
✓ Branch 3 taken 1265 times.
102744958 DBUG_PRINT("debug", ("%s_cache - pending: 0x%llx, bytes: %llu",
757 (flags.transactional ? "trx" : "stmt"),
758 (ulonglong)pending(), (ulonglong)m_cache.length()));
759
4/4
✓ Branch 0 taken 102660735 times.
✓ Branch 1 taken 85555 times.
✓ Branch 2 taken 62808031 times.
✓ Branch 3 taken 39853908 times.
102746341 return pending() == nullptr && m_cache.is_empty();
760 }
761
762 12158040 bool is_finalized() const { return flags.finalized; }
763
764 272497795 Rows_log_event *pending() const { return m_pending; }
765
766 36467480 void set_pending(Rows_log_event *const pending) { m_pending = pending; }
767
768 11 void set_incident(void) { flags.incident = true; }
769
770 5940055 bool has_incident(void) const { return flags.incident; }
771
772 11370971 bool has_xid() const {
773 // There should only be an XID event if we are transactional
774
5/6
✓ Branch 0 taken 5444673 times.
✓ Branch 1 taken 5926298 times.
✓ Branch 2 taken 265647 times.
✓ Branch 3 taken 5179026 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 11105324 times.
11370971 assert((flags.transactional && flags.with_xid) || !flags.with_xid);
775 11370971 return flags.with_xid;
776 }
777
778 5927063 bool is_trx_cache() const { return flags.transactional; }
779
780 16956447 my_off_t get_byte_position() const { return m_cache.length(); }
781
782 34219621 void cache_state_checkpoint(my_off_t pos_to_checkpoint) {
783 // We only need to store the cache state for pos > 0
784
2/2
✓ Branch 0 taken 22667864 times.
✓ Branch 1 taken 11551757 times.
34219621 if (pos_to_checkpoint) {
785 cache_state state;
786 22667864 state.with_rbr = flags.with_rbr;
787 22667864 state.with_sbr = flags.with_sbr;
788 22667864 state.with_start = flags.with_start;
789 22667864 state.with_end = flags.with_end;
790 22667864 state.with_content = flags.with_content;
791 22667864 state.event_counter = event_counter;
792
1/2
✓ Branch 0 taken 22668016 times.
✗ Branch 1 not taken.
22667864 cache_state_map[pos_to_checkpoint] = state;
793 }
794 34219773 }
795
796 8370 void cache_state_rollback(my_off_t pos_to_rollback) {
797
2/2
✓ Branch 0 taken 7814 times.
✓ Branch 1 taken 556 times.
8370 if (pos_to_rollback) {
798 7814 std::map<my_off_t, cache_state>::iterator it;
799
1/2
✓ Branch 0 taken 7814 times.
✗ Branch 1 not taken.
7814 it = cache_state_map.find(pos_to_rollback);
800
1/2
✓ Branch 0 taken 7814 times.
✗ Branch 1 not taken.
7814 if (it != cache_state_map.end()) {
801 7814 flags.with_rbr = it->second.with_rbr;
802 7814 flags.with_sbr = it->second.with_sbr;
803 7814 flags.with_start = it->second.with_start;
804 7814 flags.with_end = it->second.with_end;
805 7814 flags.with_content = it->second.with_content;
806 7814 event_counter = it->second.event_counter;
807 } else
808 assert(it == cache_state_map.end());
809 }
810 // Rolling back to pos == 0 means cleaning up the cache.
811 else {
812 556 flags.with_rbr = false;
813 556 flags.with_sbr = false;
814 556 flags.with_start = false;
815 556 flags.with_end = false;
816 556 flags.with_content = false;
817 556 event_counter = 0;
818 }
819 8370 }
820
821 /**
822 Reset the cache to unused state when the transaction is finished. It
823 drops all data in the cache and clears the flags of the transaction state.
824 */
825 5931921 virtual void reset() {
826 5931921 compute_statistics();
827 5931922 remove_pending_event();
828
829
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5931922 times.
5931922 if (m_cache.reset()) {
830 LogErr(WARNING_LEVEL, ER_BINLOG_CANT_RESIZE_CACHE);
831 }
832
833 5931922 flags.incident = false;
834 5931922 flags.with_xid = false;
835 5931922 flags.immediate = false;
836 5931922 flags.finalized = false;
837 5931922 flags.with_sbr = false;
838 5931922 flags.with_rbr = false;
839 5931922 flags.with_start = false;
840 5931922 flags.with_end = false;
841 5931922 flags.with_content = false;
842
843 /*
844 The truncate function calls reinit_io_cache that calls my_b_flush_io_cache
845 which may increase disk_writes. This breaks the disk_writes use by the
846 binary log which aims to compute the ratio between in-memory cache usage
847 and disk cache usage. To avoid this undesirable behavior, we reset the
848 variable after truncating the cache.
849 */
850 5931922 cache_state_map.clear();
851 5931922 event_counter = 0;
852 5931922 m_compressed_size = 0;
853 5931922 m_decompressed_size = 0;
854 5931922 m_compression_type = binary_log::transaction::compression::NONE;
855
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5931922 times.
5931922 assert(is_binlog_empty());
856 5931922 }
857
858 /**
859 Returns information about the cache content with respect to
860 the binlog_format of the events.
861
862 This will be used to set a flag on GTID_LOG_EVENT stating that the
863 transaction may have SBR statements or not, but the binlog dump
864 will show this flag as "rbr_only" when it is not set. That's why
865 an empty transaction should return true below, or else an empty
866 transaction would be assumed as "rbr_only" even not having RBR
867 events.
868
869 When dumping a binary log content using mysqlbinlog client program,
870 for any transaction assumed as "rbr_only" it will be printed a
871 statement changing the transaction isolation level to READ COMMITTED.
872 It doesn't make sense to have an empty transaction "requiring" this
873 isolation level change.
874
875 @return true The cache have SBR events or is empty.
876 @return false The cache contains a transaction with no SBR events.
877 */
878
4/4
✓ Branch 0 taken 5367249 times.
✓ Branch 1 taken 559969 times.
✓ Branch 2 taken 56251 times.
✓ Branch 3 taken 5310998 times.
5927218 bool may_have_sbr_stmts() { return flags.with_sbr || !flags.with_rbr; }
879
880 /**
881 Check if the binlog cache contains an empty transaction, which has
882 two binlog events "BEGIN" and "COMMIT".
883
884 @return true The binlog cache contains an empty transaction.
885 @return false Otherwise.
886 */
887 884 bool has_empty_transaction() {
888 /*
889 The empty transaction has two events in trx/stmt binlog cache
890 and no changes: one is a transaction start and other is a transaction
891 end (there should be no SBR changing content and no RBR events).
892 */
893
2/2
✓ Branch 0 taken 470 times.
✓ Branch 1 taken 414 times.
884 if (flags.with_start && // Has transaction start statement
894
1/2
✓ Branch 0 taken 470 times.
✗ Branch 1 not taken.
470 flags.with_end && // Has transaction end statement
895
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 460 times.
470 !flags.with_content) // Has no other content than START/END
896 {
897
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 assert(event_counter == 2); // Two events in the cache only
898
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 assert(!flags.with_sbr); // No statements changing content
899
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 assert(!flags.with_rbr); // No rows changing content
900
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 assert(!flags.immediate); // Not a DDL
901
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 assert(!flags.with_xid); // Not a XID trx and not an atomic DDL Query
902 10 return true;
903 }
904 874 return false;
905 }
906
907 /**
908 Check if the binlog cache is empty or contains an empty transaction,
909 which has two binlog events "BEGIN" and "COMMIT".
910
911 @return true The binlog cache is empty or contains an empty transaction.
912 @return false Otherwise.
913 */
914 894 bool is_empty_or_has_empty_transaction() {
915
4/4
✓ Branch 0 taken 884 times.
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 874 times.
894 return is_binlog_empty() || has_empty_transaction();
916 }
917
918 protected:
919 /*
920 This structure should have all cache variables/flags that should be restored
921 when a ROLLBACK TO SAVEPOINT statement be executed.
922 */
923 struct cache_state {
924 bool with_sbr;
925 bool with_rbr;
926 bool with_start;
927 bool with_end;
928 bool with_content;
929 size_t event_counter;
930 };
931 /*
932 For every SAVEPOINT used, we will store a cache_state for the current
933 binlog cache position. So, if a ROLLBACK TO SAVEPOINT is used, we can
934 restore the cache_state values after truncating the binlog cache.
935 */
936 std::map<my_off_t, cache_state> cache_state_map;
937 /*
938 In order to compute the transaction size (because of possible extra checksum
939 bytes), we need to keep track of how many events are in the binlog cache.
940 */
941 size_t event_counter = 0;
942
943 size_t m_compressed_size = 0;
944 size_t m_decompressed_size = 0;
945 binary_log::transaction::compression::type m_compression_type =
946 binary_log::transaction::compression::type::NONE;
947 /*
948 It truncates the cache to a certain position. This includes deleting the
949 pending event. It corresponds to rollback statement or rollback to
950 a savepoint. It doesn't change transaction state.
951 */
952 8370 void truncate(my_off_t pos) {
953
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8370 times.
8370 DBUG_PRINT("info", ("truncating to position %lu", (ulong)pos));
954 8370 remove_pending_event();
955
956 // TODO: check the return value.
957 8370 (void)m_cache.truncate(pos);
958 8370 }
959
960 /**
961 Flush pending event to the cache buffer.
962 */
963 5927067 int flush_pending_event(THD *thd) {
964
2/2
✓ Branch 0 taken 15047 times.
✓ Branch 1 taken 5912020 times.
5927067 if (m_pending) {
965 15047 m_pending->set_flags(Rows_log_event::STMT_END_F);
966
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15047 times.
15047 if (int error = write_event(m_pending)) return error;
967 15047 thd->clear_binlog_table_maps();
968 }
969 5927067 return 0;
970 }
971
972 /**
973 Remove the pending event.
974 */
975 5948322 int remove_pending_event() {
976
2/2
✓ Branch 0 taken 15746 times.
✓ Branch 1 taken 5932576 times.
5948322 delete m_pending;
977 5948322 m_pending = nullptr;
978 5948322 return 0;
979 }
980 struct Flags {
981 /*
982 Defines if this is either a trx-cache or stmt-cache, respectively, a
983 transactional or non-transactional cache.
984 */
985 bool transactional : 1;
986
987 /*
988 This indicates that some events did not get into the cache and most likely
989 it is corrupted.
990 */
991 bool incident : 1;
992
993 /*
994 This indicates that the cache should be written without BEGIN/END.
995 */
996 bool immediate : 1;
997
998 /*
999 This flag indicates that the buffer was finalized and has to be
1000 flushed to disk.
1001 */
1002 bool finalized : 1;
1003
1004 /*
1005 This indicates that either the cache contain an XID event, or it's
1006 an atomic DDL Query-log-event. In the latter case the flag is set up
1007 on the statement level, namely when the Query-log-event is cached
1008 at time the DDL transaction is not committing.
1009 The flag therefore gets reset when the cache is cleaned due to
1010 the statement rollback, e.g in case of a DDL post-caching execution
1011 error.
1012 Any statement scope flag among other things must consider its
1013 reset policy when the statement is rolled back.
1014 */
1015 bool with_xid : 1;
1016
1017 /*
1018 This indicates that the cache contain statements changing content.
1019 */
1020 bool with_sbr : 1;
1021
1022 /*
1023 This indicates that the cache contain RBR event changing content.
1024 */
1025 bool with_rbr : 1;
1026
1027 /*
1028 This indicates that the cache contain s transaction start statement.
1029 */
1030 bool with_start : 1;
1031
1032 /*
1033 This indicates that the cache contain a transaction end event.
1034 */
1035 bool with_end : 1;
1036
1037 /*
1038 This indicates that the cache contain content other than START/END.
1039 */
1040 bool with_content : 1;
1041 } flags;
1042
1043 virtual bool compress(THD *);
1044
1045 private:
1046 /*
1047 Storage for byte data. This binlog_cache_data will serialize
1048 events into bytes and put them into m_cache.
1049 */
1050 Binlog_cache_storage m_cache;
1051
1052 /*
1053 Pending binrows event. This event is the event where the rows are currently
1054 written.
1055 */
1056 Rows_log_event *m_pending;
1057
1058 /**
1059 This function computes binlog cache and disk usage.
1060 */
1061 5931922 void compute_statistics() {
1062
2/2
✓ Branch 0 taken 5931591 times.
✓ Branch 1 taken 331 times.
5931922 if (!is_binlog_empty()) {
1063 5931591 (*ptr_binlog_cache_use)++;
1064
2/2
✓ Branch 0 taken 56212 times.
✓ Branch 1 taken 5875379 times.
5931591 if (m_cache.disk_writes() != 0) (*ptr_binlog_cache_disk_use)++;
1065 }
1066 5931922 }
1067
1068 /*
1069 Stores a pointer to the status variable that keeps track of the in-memory
1070 cache usage. This corresponds to either
1071 . binlog_cache_use or binlog_stmt_cache_use.
1072 */
1073 ulong *ptr_binlog_cache_use;
1074
1075 /*
1076 Stores a pointer to the status variable that keeps track of the disk
1077 cache usage. This corresponds to either
1078 . binlog_cache_disk_use or binlog_stmt_cache_disk_use.
1079 */
1080 ulong *ptr_binlog_cache_disk_use;
1081
1082 binlog_cache_data &operator=(const binlog_cache_data &info);
1083 binlog_cache_data(const binlog_cache_data &info);
1084 };
1085
1086 class binlog_stmt_cache_data : public binlog_cache_data {
1087 public:
1088 46674 binlog_stmt_cache_data(bool trx_cache_arg, ulong *ptr_binlog_cache_use_arg,
1089 ulong *ptr_binlog_cache_disk_use_arg)
1090 46674 : binlog_cache_data(trx_cache_arg, ptr_binlog_cache_use_arg,
1091 46674 ptr_binlog_cache_disk_use_arg) {}
1092
1093 using binlog_cache_data::finalize;
1094
1095 int finalize(THD *thd);
1096 };
1097
1098 481347 int binlog_stmt_cache_data::finalize(THD *thd) {
1099
2/2
✓ Branch 0 taken 103629 times.
✓ Branch 1 taken 377718 times.
481347 if (flags.immediate) {
1100
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 103629 times.
103629 if (int error = finalize(thd, nullptr)) return error;
1101 } else {
1102 Query_log_event end_evt(thd, STRING_WITH_LEN("COMMIT"), false, false, true,
1103
1/2
✓ Branch 0 taken 378117 times.
✗ Branch 1 not taken.
377718 0, true);
1104
2/4
✓ Branch 0 taken 378093 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 378093 times.
378117 if (int error = finalize(thd, &end_evt)) return error;
1105
1/2
✓ Branch 0 taken 378075 times.
✗ Branch 1 not taken.
378093 }
1106 481704 return 0;
1107 }
1108
1109 class binlog_trx_cache_data : public binlog_cache_data {
1110 public:
1111 46672 binlog_trx_cache_data(bool trx_cache_arg, ulong *ptr_binlog_cache_use_arg,
1112 ulong *ptr_binlog_cache_disk_use_arg)
1113 46672 : binlog_cache_data(trx_cache_arg, ptr_binlog_cache_use_arg,
1114 ptr_binlog_cache_disk_use_arg),
1115 46677 m_cannot_rollback(false),
1116 46672 before_stmt_pos(MY_OFF_T_UNDEF) {}
1117
1118 5450072 void reset() override {
1119
1/2
✓ Branch 0 taken 5450072 times.
✗ Branch 1 not taken.
5450072 DBUG_TRACE;
1120
5/8
✓ Branch 0 taken 5450072 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5450072 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 78 times.
✓ Branch 5 taken 5449994 times.
✓ Branch 6 taken 78 times.
✗ Branch 7 not taken.
5450072 DBUG_PRINT("enter", ("before_stmt_pos: %llu", (ulonglong)before_stmt_pos));
1121 5450072 m_cannot_rollback = false;
1122 5450072 before_stmt_pos = MY_OFF_T_UNDEF;
1123
1/2
✓ Branch 0 taken 5450072 times.
✗ Branch 1 not taken.
5450072 binlog_cache_data::reset();
1124
5/8
✓ Branch 0 taken 5450072 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5450072 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 78 times.
✓ Branch 5 taken 5449994 times.
✓ Branch 6 taken 78 times.
✗ Branch 7 not taken.
5450072 DBUG_PRINT("return", ("before_stmt_pos: %llu", (ulonglong)before_stmt_pos));
1125 10900144 return;
1126 5450072 }
1127
1128 19862 bool cannot_rollback() const { return m_cannot_rollback; }
1129
1130 1160 void set_cannot_rollback() { m_cannot_rollback = true; }
1131
1132 11032682 my_off_t get_prev_position() const { return before_stmt_pos; }
1133
1134 23189923 void set_prev_position(my_off_t pos) {
1135
1/2
✓ Branch 0 taken 23190501 times.
✗ Branch 1 not taken.
23189923 DBUG_TRACE;
1136
5/8
✓ Branch 0 taken 23190307 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23190421 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 219 times.
✓ Branch 5 taken 23190202 times.
✓ Branch 6 taken 219 times.
✗ Branch 7 not taken.
23190501 DBUG_PRINT("enter", ("before_stmt_pos: %llu", (ulonglong)before_stmt_pos));
1137 23190421 before_stmt_pos = pos;
1138
1/2
✓ Branch 0 taken 23190507 times.
✗ Branch 1 not taken.
23190421 cache_state_checkpoint(before_stmt_pos);
1139
5/8
✓ Branch 0 taken 23190121 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23190285 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 219 times.
✓ Branch 5 taken 23190066 times.
✓ Branch 6 taken 194 times.
✗ Branch 7 not taken.
23190507 DBUG_PRINT("return", ("before_stmt_pos: %llu", (ulonglong)before_stmt_pos));
1140 46380888 return;
1141 23190260 }
1142
1143 732 void restore_prev_position() {
1144
1/2
✓ Branch 0 taken 732 times.
✗ Branch 1 not taken.
732 DBUG_TRACE;
1145
3/8
✓ Branch 0 taken 732 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 732 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 732 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
732 DBUG_PRINT("enter", ("before_stmt_pos: %llu", (ulonglong)before_stmt_pos));
1146
1/2
✓ Branch 0 taken 732 times.
✗ Branch 1 not taken.
732 binlog_cache_data::truncate(before_stmt_pos);
1147
1/2
✓ Branch 0 taken 732 times.
✗ Branch 1 not taken.
732 cache_state_rollback(before_stmt_pos);
1148 732 before_stmt_pos = MY_OFF_T_UNDEF;
1149 /*
1150 Binlog statement rollback clears with_xid now as the atomic DDL statement
1151 marker which can be set as early as at event creation and caching.
1152 */
1153 732 flags.with_xid = false;
1154
3/8
✓ Branch 0 taken 732 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 732 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 732 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
732 DBUG_PRINT("return", ("before_stmt_pos: %llu", (ulonglong)before_stmt_pos));
1155 1464 return;
1156 732 }
1157
1158 7638 void restore_savepoint(my_off_t pos) {
1159
1/2
✓ Branch 0 taken 7638 times.
✗ Branch 1 not taken.
7638 DBUG_TRACE;
1160
3/8
✓ Branch 0 taken 7638 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7638 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 7638 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
7638 DBUG_PRINT("enter", ("before_stmt_pos: %llu", (ulonglong)before_stmt_pos));
1161
1/2
✓ Branch 0 taken 7638 times.
✗ Branch 1 not taken.
7638 binlog_cache_data::truncate(pos);
1162
2/2
✓ Branch 0 taken 7625 times.
✓ Branch 1 taken 13 times.
7638 if (pos <= before_stmt_pos) before_stmt_pos = MY_OFF_T_UNDEF;
1163
1/2
✓ Branch 0 taken 7638 times.
✗ Branch 1 not taken.
7638 cache_state_rollback(pos);
1164
3/8
✓ Branch 0 taken 7638 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7638 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 7638 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
7638 DBUG_PRINT("return", ("before_stmt_pos: %llu", (ulonglong)before_stmt_pos));
1165 15276 return;
1166 7638 }
1167
1168 using binlog_cache_data::truncate;
1169
1170 int truncate(THD *thd, bool all);
1171
1172 private:
1173 /*
1174 It will be set true if any statement which cannot be rolled back safely
1175 is put in trx_cache.
1176 */
1177 bool m_cannot_rollback;
1178
1179 /*
1180 Binlog position before the start of the current statement.
1181 */
1182 my_off_t before_stmt_pos;
1183
1184 binlog_trx_cache_data &operator=(const binlog_trx_cache_data &info);
1185 binlog_trx_cache_data(const binlog_trx_cache_data &info);
1186 };
1187
1188 class binlog_cache_mngr {
1189 public:
1190 46675 binlog_cache_mngr(ulong *ptr_binlog_stmt_cache_use_arg,
1191 ulong *ptr_binlog_stmt_cache_disk_use_arg,
1192 ulong *ptr_binlog_cache_use_arg,
1193 ulong *ptr_binlog_cache_disk_use_arg)
1194 46675 : stmt_cache(false, ptr_binlog_stmt_cache_use_arg,
1195 ptr_binlog_stmt_cache_disk_use_arg),
1196
1/2
✓ Branch 0 taken 46677 times.
✗ Branch 1 not taken.
46674 trx_cache(true, ptr_binlog_cache_use_arg,
1197 46677 ptr_binlog_cache_disk_use_arg) {}
1198
1199 46673 bool init() {
1200 46673 return stmt_cache.open(binlog_stmt_cache_size,
1201
1/2
✓ Branch 0 taken 46677 times.
✗ Branch 1 not taken.
93354 max_binlog_stmt_cache_size) ||
1202
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 46677 times.
93354 trx_cache.open(binlog_cache_size, max_binlog_cache_size);
1203 }
1204
1205 197811455 binlog_cache_data *get_binlog_cache_data(bool is_transactional) {
1206
2/2
✓ Branch 0 taken 178709095 times.
✓ Branch 1 taken 19102360 times.
197811455 if (is_transactional)
1207 178709095 return &trx_cache;
1208 else
1209 19102360 return &stmt_cache;
1210 }
1211
1212 103772 Binlog_cache_storage *get_stmt_cache() { return stmt_cache.get_cache(); }
1213 103865 Binlog_cache_storage *get_trx_cache() { return trx_cache.get_cache(); }
1214 /**
1215 Convenience method to check if both caches are empty.
1216 */
1217 255867 bool is_binlog_empty() const {
1218
4/4
✓ Branch 0 taken 255098 times.
✓ Branch 1 taken 847 times.
✓ Branch 2 taken 247255 times.
✓ Branch 3 taken 7863 times.
255867 return stmt_cache.is_binlog_empty() && trx_cache.is_binlog_empty();
1219 }
1220
1221 /*
1222 clear stmt_cache and trx_cache if they are not empty
1223 */
1224 704 void reset() {
1225
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 702 times.
704 if (!stmt_cache.is_binlog_empty()) stmt_cache.reset();
1226
2/2
✓ Branch 0 taken 688 times.
✓ Branch 1 taken 16 times.
704 if (!trx_cache.is_binlog_empty()) trx_cache.reset();
1227 704 }
1228
1229 #ifndef NDEBUG
1230 6079064 bool dbug_any_finalized() const {
1231
3/4
✓ Branch 0 taken 6079128 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 6079035 times.
6079064 return stmt_cache.is_finalized() || trx_cache.is_finalized();
1232 }
1233 #endif
1234
1235 /*
1236 Convenience method to flush both caches to the binary log.
1237
1238 @param bytes_written Pointer to variable that will be set to the
1239 number of bytes written for the flush.
1240 @param wrote_xid Pointer to variable that will be set to @c
1241 true if any XID event was written to the
1242 binary log. Otherwise, the variable will not
1243 be touched.
1244 @return Error code on error, zero if no error.
1245 */
1246 5926417 int flush(THD *thd, my_off_t *bytes_written, bool *wrote_xid) {
1247 5926417 my_off_t stmt_bytes = 0;
1248 5926417 my_off_t trx_bytes = 0;
1249
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5926417 times.
5926417 assert(stmt_cache.has_xid() == 0);
1250
1/2
✓ Branch 0 taken 5926416 times.
✗ Branch 1 not taken.
5926417 int error = stmt_cache.flush(thd, &stmt_bytes, wrote_xid);
1251
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 5926415 times.
5926416 if (error) return error;
1252
3/4
✓ Branch 0 taken 5923765 times.
✓ Branch 1 taken 2650 times.
✓ Branch 2 taken 5923765 times.
✗ Branch 3 not taken.
5926415 DEBUG_SYNC(thd, "after_flush_stm_cache_before_flush_trx_cache");
1253
1/2
✓ Branch 0 taken 5926413 times.
✗ Branch 1 not taken.
5926415 error = trx_cache.flush(thd, &trx_bytes, wrote_xid);
1254
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 5926410 times.
5926413 if (error) return error;
1255 5926410 *bytes_written = stmt_bytes + trx_bytes;
1256 5926410 return 0;
1257 }
1258
1259 /**
1260 Check if at least one of transactions and statement binlog caches
1261 contains an empty transaction, other one is empty or contains an
1262 empty transaction.
1263
1264 @return true At least one of transactions and statement binlog
1265 caches an empty transaction, other one is empty
1266 or contains an empty transaction.
1267 @return false Otherwise.
1268 */
1269 884 bool has_empty_transaction() {
1270 884 return (trx_cache.is_empty_or_has_empty_transaction() &&
1271
3/4
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 874 times.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
894 stmt_cache.is_empty_or_has_empty_transaction() &&
1272
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
894 !is_binlog_empty());
1273 }
1274
1275 /**
1276 Check if manager contains consistent snapshot of log coordinates
1277 and gtid_executed.
1278
1279 @return true Consistent snapshot available
1280 @return false Otherwise
1281 */
1282 52042 bool has_consistent_snapshot() const {
1283 /**
1284 snapshot_gtid_executed can be empty string
1285 if gtid_mode=OFF.
1286 */
1287
1288 52042 return binlog_info.log_file_name[0] != '\0';
1289 }
1290
1291 /**
1292 Removes consistent snapshot from cache.
1293 */
1294 2085123 void drop_consistent_snapshot() {
1295 2085123 binlog_info.log_file_name[0] = '\0';
1296 2085123 snapshot_gtid_executed.clear();
1297 2085229 }
1298
1299 binlog_stmt_cache_data stmt_cache;
1300 binlog_trx_cache_data trx_cache;
1301
1302 LOG_INFO binlog_info;
1303 std::string snapshot_gtid_executed;
1304
1305 private:
1306 binlog_cache_mngr &operator=(const binlog_cache_mngr &info);
1307 binlog_cache_mngr(const binlog_cache_mngr &info);
1308 };
1309
1310 344228222 static binlog_cache_mngr *thd_get_cache_mngr(const THD *thd) {
1311 /*
1312 If opt_bin_log is not set, binlog_hton->slot == -1 and hence
1313 thd_get_ha_data(thd, hton) segfaults.
1314 */
1315
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 344228222 times.
344228222 assert(opt_bin_log);
1316 344228222 return (binlog_cache_mngr *)thd_get_ha_data(thd, binlog_hton);
1317 }
1318
1319 /**
1320 Checks if the BINLOG_CACHE_SIZE's value is greater than MAX_BINLOG_CACHE_SIZE.
1321 If this happens, the BINLOG_CACHE_SIZE is set to MAX_BINLOG_CACHE_SIZE.
1322 */
1323 11785 void check_binlog_cache_size(THD *thd) {
1324
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 11774 times.
11785 if (binlog_cache_size > max_binlog_cache_size) {
1325
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 if (thd) {
1326 11 push_warning_printf(
1327 thd, Sql_condition::SL_WARNING, ER_BINLOG_CACHE_SIZE_GREATER_THAN_MAX,
1328 ER_THD(thd, ER_BINLOG_CACHE_SIZE_GREATER_THAN_MAX),
1329 (ulong)binlog_cache_size, (ulong)max_binlog_cache_size);
1330 } else {
1331 LogErr(WARNING_LEVEL, ER_BINLOG_CACHE_SIZE_TOO_LARGE, binlog_cache_size,
1332 (ulong)max_binlog_cache_size);
1333 }
1334 11 binlog_cache_size = static_cast<ulong>(max_binlog_cache_size);
1335 }
1336 11785 }
1337
1338 /**
1339 Checks if the BINLOG_STMT_CACHE_SIZE's value is greater than
1340 MAX_BINLOG_STMT_CACHE_SIZE. If this happens, the BINLOG_STMT_CACHE_SIZE is set
1341 to MAX_BINLOG_STMT_CACHE_SIZE.
1342 */
1343 11776 void check_binlog_stmt_cache_size(THD *thd) {
1344
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 11767 times.
11776 if (binlog_stmt_cache_size > max_binlog_stmt_cache_size) {
1345
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 if (thd) {
1346 9 push_warning_printf(
1347 thd, Sql_condition::SL_WARNING,
1348 ER_BINLOG_STMT_CACHE_SIZE_GREATER_THAN_MAX,
1349 ER_THD(thd, ER_BINLOG_STMT_CACHE_SIZE_GREATER_THAN_MAX),
1350 (ulong)binlog_stmt_cache_size, (ulong)max_binlog_stmt_cache_size);
1351 } else {
1352 LogErr(WARNING_LEVEL, ER_BINLOG_STMT_CACHE_SIZE_TOO_LARGE,
1353 binlog_stmt_cache_size, (ulong)max_binlog_stmt_cache_size);
1354 }
1355 9 binlog_stmt_cache_size = static_cast<ulong>(max_binlog_stmt_cache_size);
1356 }
1357 11776 }
1358
1359 /**
1360 Check whether binlog_hton has valid slot and enabled
1361 */
1362 bool binlog_enabled() {
1363 return (binlog_hton && binlog_hton->slot != HA_SLOT_UNDEF);
1364 }
1365
1366 /*
1367 Save position of binary log transaction cache.
1368
1369 SYNPOSIS
1370 binlog_trans_log_savepos()
1371
1372 thd The thread to take the binlog data from
1373 pos Pointer to variable where the position will be stored
1374
1375 DESCRIPTION
1376
1377 Save the current position in the binary log transaction cache into
1378 the variable pointed to by 'pos'
1379 */
1380
1381 11029365 static void binlog_trans_log_savepos(THD *thd, my_off_t *pos) {
1382
1/2
✓ Branch 0 taken 11029939 times.
✗ Branch 1 not taken.
11029365 DBUG_TRACE;
1383
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11029939 times.
11029939 assert(pos != nullptr);
1384
1/2
✓ Branch 0 taken 11030130 times.
✗ Branch 1 not taken.
11029939 binlog_cache_mngr *const cache_mngr = thd_get_cache_mngr(thd);
1385
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11029866 times.
11030130 assert(mysql_bin_log.is_open());
1386
1/2
✓ Branch 0 taken 11029584 times.
✗ Branch 1 not taken.
11029866 *pos = cache_mngr->trx_cache.get_byte_position();
1387
5/8
✓ Branch 0 taken 11029554 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11029621 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 84 times.
✓ Branch 5 taken 11029537 times.
✓ Branch 6 taken 84 times.
✗ Branch 7 not taken.
11029584 DBUG_PRINT("return", ("position: %lu", (ulong)*pos));
1388
1/2
✓ Branch 0 taken 11029409 times.
✗ Branch 1 not taken.
11029621 cache_mngr->trx_cache.cache_state_checkpoint(*pos);
1389 11029409 }
1390
1391 11293 static int binlog_dummy_recover(handlerton *, XA_recover_txn *, uint,
1392 MEM_ROOT *) {
1393 11293 return 0;
1394 }
1395
1396 /**
1397 Auxiliary class to copy serialized events to the binary log and
1398 correct some of the fields that are not known until just before
1399 writing the event.
1400
1401 This class allows feeding events in parts, so it is practical to use
1402 in do_write_cache() which reads events from an IO_CACHE where events
1403 may span multiple cache pages.
1404
1405 The following fields are fixed before writing the event:
1406 - end_log_pos is set
1407 - the checksum is computed if checksums are enabled
1408 - the length is incremented by the checksum size if checksums are enabled
1409 */
1410 class Binlog_event_writer : public Basic_ostream {
1411 MYSQL_BIN_LOG::Binlog_ofile *m_binlog_file;
1412 bool have_checksum;
1413 ha_checksum initial_checksum;
1414 ha_checksum checksum;
1415 uint32 end_log_pos;
1416 THD *thd;
1417 uchar header[LOG_EVENT_HEADER_LEN];
1418 my_off_t header_len = 0;
1419 uint32 event_len = 0;
1420
1421 public:
1422 /**
1423 Constructs a new Binlog_event_writer. Should be called once before
1424 starting to flush the transaction or statement cache to the
1425 binlog.
1426
1427 @param binlog_file to write to.
1428 @param thd_arg THD to account written binlog byte statistics to
1429 */
1430 5927064 Binlog_event_writer(MYSQL_BIN_LOG::Binlog_ofile *binlog_file, THD *thd_arg)
1431 11854128 : m_binlog_file(binlog_file),
1432 5927064 have_checksum(binlog_checksum_options !=
1433 binary_log::BINLOG_CHECKSUM_ALG_OFF),
1434 11854128 initial_checksum(my_checksum(0L, nullptr, 0)),
1435 5927064 checksum(initial_checksum),
1436 5927064 end_log_pos(binlog_file->position()),
1437
1/2
✓ Branch 0 taken 5927064 times.
✗ Branch 1 not taken.
5927064 thd(thd_arg) {
1438 // Simulate checksum error
1439
3/4
✓ Branch 0 taken 5927064 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 5927063 times.
5927064 if (DBUG_EVALUATE_IF("fault_injection_crc_value", 1, 0)) checksum--;
1440 5927064 }
1441
1442 53969130 void update_header() {
1443 53969130 event_len = uint4korr(header + EVENT_LEN_OFFSET);
1444
1445 // Increase end_log_pos
1446 53969130 end_log_pos += event_len;
1447
1448 // Update event length if it has checksum
1449
2/2
✓ Branch 0 taken 53968848 times.
✓ Branch 1 taken 282 times.
53969130 if (have_checksum) {
1450 53968848 int4store(header + EVENT_LEN_OFFSET, event_len + BINLOG_CHECKSUM_LEN);
1451 53968848 end_log_pos += BINLOG_CHECKSUM_LEN;
1452 }
1453
1454 // Store end_log_pos
1455 53969130 int4store(header + LOG_POS_OFFSET, end_log_pos);
1456 // update the checksum
1457
2/2
✓ Branch 0 taken 53968848 times.
✓ Branch 1 taken 282 times.
53969130 if (have_checksum) checksum = my_checksum(checksum, header, header_len);
1458 53969130 }
1459
1460 24323811 bool write(const unsigned char *buffer, my_off_t length) override {
1461
1/2
✓ Branch 0 taken 24323811 times.
✗ Branch 1 not taken.
24323811 DBUG_TRACE;
1462
1463
2/2
✓ Branch 0 taken 114479169 times.
✓ Branch 1 taken 24323811 times.
138802980 while (length > 0) {
1464 /* Write event header into binlog */
1465
2/2
✓ Branch 0 taken 53982819 times.
✓ Branch 1 taken 60496350 times.
114479169 if (event_len == 0) {
1466 /* data in the buf may be smaller than header size.*/
1467 uint32 header_incr =
1468 53982819 std::min<uint32>(LOG_EVENT_HEADER_LEN - header_len, length);
1469
1470 53982819 memcpy(header + header_len, buffer, header_incr);
1471 53982819 header_len += header_incr;
1472 53982819 buffer += header_incr;
1473 53982819 length -= header_incr;
1474
1475
2/2
✓ Branch 0 taken 53969130 times.
✓ Branch 1 taken 13689 times.
53982819 if (header_len == LOG_EVENT_HEADER_LEN) {
1476
1/2
✓ Branch 0 taken 53969130 times.
✗ Branch 1 not taken.
53969130 update_header();
1477
2/4
✓ Branch 0 taken 53969130 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 53969130 times.
53969130 if (m_binlog_file->write(header, header_len)) return true;
1478
1479 53969130 event_len -= header_len;
1480 53969130 header_len = 0;
1481 }
1482 } else {
1483 60496350 my_off_t write_bytes = std::min<uint64>(length, event_len);
1484
1485
2/4
✓ Branch 0 taken 60496350 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 60496350 times.
60496350 if (m_binlog_file->write(buffer, write_bytes)) return true;
1486
1487 // update the checksum
1488
2/2
✓ Branch 0 taken 60495989 times.
✓ Branch 1 taken 361 times.
60496350 if (have_checksum)
1489
1/2
✓ Branch 0 taken 60495989 times.
✗ Branch 1 not taken.
60495989 checksum = my_checksum(checksum, buffer, write_bytes);
1490
1491 60496350 event_len -= write_bytes;
1492 60496350 length -= write_bytes;
1493 60496350 buffer += write_bytes;
1494
1495 // The whole event is copied, now add the checksum
1496
4/4
✓ Branch 0 taken 60495989 times.
✓ Branch 1 taken 361 times.
✓ Branch 2 taken 53968848 times.
✓ Branch 3 taken 6527141 times.
60496350 if (have_checksum && event_len == 0) {
1497 uchar checksum_buf[BINLOG_CHECKSUM_LEN];
1498
1499 53968848 int4store(checksum_buf, checksum);
1500
2/4
✓ Branch 0 taken 53968848 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 53968848 times.
53968848 if (m_binlog_file->write(checksum_buf, BINLOG_CHECKSUM_LEN))
1501 return true;
1502 53968848 checksum = initial_checksum;
1503 }
1504 }
1505 }
1506 24323811 return false;
1507 24323811 }
1508 /**
1509 Returns true if per event checksum is enabled.
1510 */
1511 5927166 bool is_checksum_enabled() { return have_checksum; }
1512 };
1513
1514 /*
1515 this function is mostly a placeholder.
1516 conceptually, binlog initialization (now mostly done in MYSQL_BIN_LOG::open)
1517 should be moved here.
1518 */
1519
1520 11902 static int binlog_init(void *p) {
1521 11902 binlog_hton = (handlerton *)p;
1522
2/2
✓ Branch 0 taken 11357 times.
✓ Branch 1 taken 545 times.
11902 binlog_hton->state = opt_bin_log ? SHOW_OPTION_YES : SHOW_OPTION_NO;
1523 11902 binlog_hton->db_type = DB_TYPE_BINLOG;
1524 11902 binlog_hton->savepoint_offset = sizeof(my_off_t);
1525 11902 binlog_hton->close_connection = binlog_close_connection;
1526 11902 binlog_hton->savepoint_set = binlog_savepoint_set;
1527 11902 binlog_hton->savepoint_rollback = binlog_savepoint_rollback;
1528 11902 binlog_hton->savepoint_rollback_can_release_mdl =
1529 binlog_savepoint_rollback_can_release_mdl;
1530 11902 binlog_hton->commit = binlog_commit;
1531 11902 binlog_hton->rollback = binlog_rollback;
1532 11902 binlog_hton->prepare = binlog_prepare;
1533 11902 binlog_hton->start_consistent_snapshot = binlog_start_consistent_snapshot;
1534 11902 binlog_hton->clone_consistent_snapshot = binlog_clone_consistent_snapshot;
1535 11902 binlog_hton->set_prepared_in_tc = binlog_set_prepared_in_tc;
1536 11902 binlog_hton->recover = binlog_dummy_recover;
1537 11902 binlog_hton->flags = HTON_NOT_USER_SELECTABLE | HTON_HIDDEN;
1538 11902 return 0;
1539 }
1540
1541 10286 static int binlog_deinit(void *) {
1542 /* Using binlog as TC after the binlog has been unloaded, won't work */
1543
2/2
✓ Branch 0 taken 9814 times.
✓ Branch 1 taken 472 times.
10286 if (tc_log == &mysql_bin_log) tc_log = nullptr;
1544 10286 binlog_hton = nullptr;
1545 10286 return 0;
1546 }
1547
1548 45194 static int binlog_close_connection(handlerton *, THD *thd) {
1549
1/2
✓ Branch 0 taken 45195 times.
✗ Branch 1 not taken.
45194 DBUG_TRACE;
1550
1/2
✓ Branch 0 taken 45195 times.
✗ Branch 1 not taken.
45195 binlog_cache_mngr *const cache_mngr = thd_get_cache_mngr(thd);
1551
2/4
✓ Branch 0 taken 45195 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 45195 times.
45195 assert(cache_mngr->is_binlog_empty());
1552
5/8
✓ Branch 0 taken 45195 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 45195 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 45194 times.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
45195 DBUG_PRINT("debug", ("Set ha_data slot %d to 0x%llx", binlog_hton->slot,
1553 (ulonglong) nullptr));
1554
1/2
✓ Branch 0 taken 45195 times.
✗ Branch 1 not taken.
45195 thd_set_ha_data(thd, binlog_hton, nullptr);
1555 45195 cache_mngr->~binlog_cache_mngr();
1556
1/2
✓ Branch 0 taken 45194 times.
✗ Branch 1 not taken.
45194 my_free(cache_mngr);
1557 45195 return 0;
1558 45194 }
1559
1560 48773204 int binlog_cache_data::write_event(Log_event *ev) {
1561
1/2
✓ Branch 0 taken 48775238 times.
✗ Branch 1 not taken.
48773204 DBUG_TRACE;
1562
1563
2/2
✓ Branch 0 taken 48405987 times.
✓ Branch 1 taken 369251 times.
48775238 if (ev != nullptr) {
1564
2/6
✓ Branch 0 taken 48405724 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 48405724 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
48405987 DBUG_EXECUTE_IF("simulate_disk_full_at_flush_pending",
1565 { DBUG_SET("+d,simulate_file_write_error"); });
1566
1567
3/4
✓ Branch 0 taken 48406075 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 61 times.
✓ Branch 3 taken 48406014 times.
48405724 if (binary_event_serialize(ev, &m_cache)) {
1568
2/10
✓ Branch 0 taken 61 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 61 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
61 DBUG_EXECUTE_IF("simulate_disk_full_at_flush_pending", {
1569 DBUG_SET("-d,simulate_file_write_error");
1570 DBUG_SET("-d,simulate_disk_full_at_flush_pending");
1571 /*
1572 after +d,simulate_file_write_error the local cache
1573 is in unsane state. Since -d,simulate_file_write_error
1574 revokes the first simulation do_write_cache()
1575 can't be run without facing an assert.
1576 So it's blocked with the following 2nd simulation:
1577 */
1578 DBUG_SET("+d,simulate_do_write_cache_failure");
1579 });
1580 61 return 1;
1581 }
1582
6/6
✓ Branch 0 taken 43285911 times.
✓ Branch 1 taken 5120097 times.
✓ Branch 2 taken 678 times.
✓ Branch 3 taken 43285369 times.
✓ Branch 4 taken 5120771 times.
✓ Branch 5 taken 43285373 times.
91692061 if (ev->get_type_code() == binary_log::XID_EVENT ||
1583 43285911 ev->get_type_code() == binary_log::XA_PREPARE_LOG_EVENT)
1584 5120771 flags.with_xid = true;
1585
2/2
✓ Branch 0 taken 103854 times.
✓ Branch 1 taken 48302318 times.
48406144 if (ev->is_using_immediate_logging()) flags.immediate = true;
1586 /* DDL gets marked as xid-requiring at its caching. */
1587
2/2
✓ Branch 0 taken 265694 times.
✓ Branch 1 taken 48140546 times.
48406172 if (is_atomic_ddl_event(ev)) flags.with_xid = true;
1588 /* With respect to the event type being written */
1589
3/4
✓ Branch 0 taken 48406019 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 771536 times.
✓ Branch 3 taken 47634483 times.
48406240 if (ev->is_sbr_logging_format()) flags.with_sbr = true;
1590
3/4
✓ Branch 0 taken 48405366 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 36491829 times.
✓ Branch 3 taken 11913537 times.
48406019 if (ev->is_rbr_logging_format()) flags.with_rbr = true;
1591 /* With respect to empty transactions */
1592
3/4
✓ Branch 0 taken 48405379 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5562375 times.
✓ Branch 3 taken 42843004 times.
48405366 if (ev->starts_group()) flags.with_start = true;
1593
3/4
✓ Branch 0 taken 48405612 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5558640 times.
✓ Branch 3 taken 42846972 times.
48405379 if (ev->ends_group()) flags.with_end = true;
1594
8/10
✓ Branch 0 taken 48406160 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 42843543 times.
✓ Branch 3 taken 5562617 times.
✓ Branch 4 taken 42843587 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 37284978 times.
✓ Branch 7 taken 5558609 times.
✓ Branch 8 taken 37284995 times.
✓ Branch 9 taken 11121209 times.
48405612 if (!ev->starts_group() && !ev->ends_group()) flags.with_content = true;
1595 48406204 event_counter++;
1596
5/8
✓ Branch 0 taken 48405215 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 48405350 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 151 times.
✓ Branch 5 taken 48405199 times.
✓ Branch 6 taken 232 times.
✗ Branch 7 not taken.
48406204 DBUG_PRINT("debug",
1597 ("event_counter= %lu", static_cast<ulong>(event_counter)));
1598 }
1599 48774682 return 0;
1600 48774743 }
1601
1602 5823408 bool MYSQL_BIN_LOG::assign_automatic_gtids_to_flush_group(THD *first_seen) {
1603
1/2
✓ Branch 0 taken 5823408 times.
✗ Branch 1 not taken.
5823408 DBUG_TRACE;
1604 5823408 bool error = false;
1605 5823408 bool is_global_sid_locked = false;
1606 5823408 rpl_sidno locked_sidno = 0;
1607
1608
2/2
✓ Branch 0 taken 5926417 times.
✓ Branch 1 taken 5823408 times.
11749825 for (THD *head = first_seen; head; head = head->next_to_commit) {
1609
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5926417 times.
5926417 assert(head->variables.gtid_next.type != UNDEFINED_GTID);
1610
1611 /* Generate GTID */
1612
2/2
✓ Branch 0 taken 5571331 times.
✓ Branch 1 taken 355086 times.
5926417 if (head->variables.gtid_next.type == AUTOMATIC_GTID) {
1613
2/2
✓ Branch 0 taken 5484182 times.
✓ Branch 1 taken 87149 times.
5571331 if (!is_global_sid_locked) {
1614
1/2
✓ Branch 0 taken 5484182 times.
✗ Branch 1 not taken.
5484182 global_sid_lock->rdlock();
1615 5484182 is_global_sid_locked = true;
1616 }
1617
3/6
✓ Branch 0 taken 5571331 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5571331 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5571331 times.
✗ Branch 5 not taken.
5571331 if (gtid_state->generate_automatic_gtid(
1618 head,
1619 head->get_transaction()->get_rpl_transaction_ctx()->get_sidno(),
1620 head->get_transaction()->get_rpl_transaction_ctx()->get_gno(),
1621
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 5571330 times.
5571331 &locked_sidno) != RETURN_STATUS_OK) {
1622 1 head->commit_error = THD::CE_FLUSH_GNO_EXHAUSTED_ERROR;
1623 1 error = true;
1624 }
1625 } else {
1626
3/8
✓ Branch 0 taken 355086 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 355086 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 355086 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
355086 DBUG_PRINT("info",
1627 ("thd->variables.gtid_next.type=%d "
1628 "thd->owned_gtid.sidno=%d",
1629 head->variables.gtid_next.type, head->owned_gtid.sidno));
1630
2/2
✓ Branch 0 taken 84447 times.
✓ Branch 1 taken 270639 times.
355086 if (head->variables.gtid_next.type == ASSIGNED_GTID)
1631
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 84447 times.
84447 assert(head->owned_gtid.sidno > 0);
1632 else {
1633
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 270639 times.
270639 assert(head->variables.gtid_next.type == ANONYMOUS_GTID);
1634
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 270639 times.
270639 assert(head->owned_gtid.sidno == THD::OWNED_SIDNO_ANONYMOUS);
1635 }
1636 }
1637 }
1638
1639
3/4
✓ Branch 0 taken 119313 times.
✓ Branch 1 taken 5704095 times.
✓ Branch 2 taken 119313 times.
✗ Branch 3 not taken.
5823408 if (locked_sidno > 0) gtid_state->unlock_sidno(locked_sidno);
1640
1641
3/4
✓ Branch 0 taken 5484182 times.
✓ Branch 1 taken 339226 times.
✓ Branch 2 taken 5484182 times.
✗ Branch 3 not taken.
5823408 if (is_global_sid_locked) global_sid_lock->unlock();
1642
1643 5823408 return error;
1644 5823408 }
1645
1646 /**
1647 Write the Gtid_log_event to the binary log (prior to writing the
1648 statement or transaction cache).
1649
1650 @param thd Thread that is committing.
1651 @param cache_data The cache that is flushing.
1652 @param writer The event will be written to this Binlog_event_writer object.
1653
1654 @retval false Success.
1655 @retval true Error.
1656 */
1657 5927063 bool MYSQL_BIN_LOG::write_transaction(THD *thd, binlog_cache_data *cache_data,
1658 Binlog_event_writer *writer) {
1659
1/2
✓ Branch 0 taken 5927063 times.
✗ Branch 1 not taken.
5927063 DBUG_TRACE;
1660
1661 /*
1662 The GTID for the THD was assigned at
1663 assign_automatic_gtids_to_flush_group()
1664 */
1665
3/4
✓ Branch 0 taken 203805 times.
✓ Branch 1 taken 5723258 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 203805 times.
5927063 assert(thd->owned_gtid.sidno == THD::OWNED_SIDNO_ANONYMOUS ||
1666 thd->owned_gtid.sidno > 0);
1667
1668 int64 sequence_number, last_committed;
1669 /* Generate logical timestamps for MTS */
1670
1/2
✓ Branch 0 taken 5927063 times.
✗ Branch 1 not taken.
5927063 m_dependency_tracker.get_dependency(thd, sequence_number, last_committed);
1671
1672 /*
1673 In case both the transaction cache and the statement cache are
1674 non-empty, both will be flushed in sequence and logged as
1675 different transactions. Then the second transaction must only
1676 be executed after the first one has committed. Therefore, we
1677 need to set last_committed for the second transaction equal to
1678 last_committed for the first transaction. This is done in
1679 binlog_cache_data::flush. binlog_cache_data::flush uses the
1680 condition trn_ctx->last_committed==SEQ_UNINIT to detect this
1681 situation, hence the need to set it here.
1682 */
1683 5927063 thd->get_transaction()->last_committed = SEQ_UNINIT;
1684
1685 /*
1686 For delayed replication and also for the purpose of lag monitoring,
1687 we assume that the commit timestamp of the transaction is the time of
1688 executing this code (the time of writing the Gtid_log_event to the binary
1689 log).
1690 */
1691 5927063 ulonglong immediate_commit_timestamp = my_micro_time();
1692
1693 /*
1694 When the original_commit_timestamp session variable is set to a value
1695 other than UNDEFINED_COMMIT_TIMESTAMP, it means that either the timestamp
1696 is known ( > 0 ) or the timestamp is not known ( == 0 ).
1697 */
1698 5927063 ulonglong original_commit_timestamp =
1699 thd->variables.original_commit_timestamp;
1700 /*
1701 When original_commit_timestamp == UNDEFINED_COMMIT_TIMESTAMP, we assume
1702 that:
1703 a) it is not known if this thread is a slave applier ( = 0 );
1704 b) this is a new transaction ( = immediate_commit_timestamp);
1705 */
1706
2/2
✓ Branch 0 taken 5590890 times.
✓ Branch 1 taken 336173 times.
5927063 if (original_commit_timestamp == UNDEFINED_COMMIT_TIMESTAMP) {
1707 /*
1708 When applying a transaction using replication, assume that the
1709 original commit timestamp is not known (the transaction wasn't
1710 originated on the current server).
1711 */
1712
6/6
✓ Branch 0 taken 5590763 times.
✓ Branch 1 taken 127 times.
✓ Branch 2 taken 46 times.
✓ Branch 3 taken 5590717 times.
✓ Branch 4 taken 173 times.
✓ Branch 5 taken 5590717 times.
5590890 if (thd->slave_thread || thd->is_binlog_applier()) {
1713 173 original_commit_timestamp = 0;
1714 } else
1715 /* Assume that this transaction is original from this server */
1716 {
1717
2/4
✓ Branch 0 taken 5590717 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5590717 times.
5590717 DBUG_EXECUTE_IF("rpl_invalid_gtid_timestamp",
1718 // add one our to the commit timestamps
1719 immediate_commit_timestamp += 3600000000;);
1720 5590717 original_commit_timestamp = immediate_commit_timestamp;
1721 }
1722 } else {
1723 // Clear the session variable to have cleared states for next transaction.
1724 336173 thd->variables.original_commit_timestamp = UNDEFINED_COMMIT_TIMESTAMP;
1725 }
1726
1727 uint32_t trx_immediate_server_version =
1728 5927063 do_server_version_int(::server_version);
1729 // Clear the session variable to have cleared states for next transaction.
1730 5927063 thd->variables.immediate_server_version = UNDEFINED_SERVER_VERSION;
1731
3/4
✓ Branch 0 taken 5927063 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 5927061 times.
5927063 DBUG_EXECUTE_IF("fixed_server_version",
1732 trx_immediate_server_version = 888888;);
1733
2/4
✓ Branch 0 taken 5927063 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5927063 times.
5927063 DBUG_EXECUTE_IF("gr_fixed_server_version",
1734 trx_immediate_server_version = 777777;);
1735
1736 /*
1737 When the original_server_version session variable is set to a value
1738 other than UNDEFINED_SERVER_VERSION, it means that either the
1739 server version is known or the server_version is not known
1740 (UNKNOWN_SERVER_VERSION).
1741 */
1742 5927063 uint32_t trx_original_server_version = thd->variables.original_server_version;
1743
1744 /*
1745 When original_server_version == UNDEFINED_SERVER_VERSION, we assume
1746 that:
1747 a) it is not known if this thread is a slave applier ( = 0 );
1748 b) this is a new transaction ( = ::server_version);
1749 */
1750
2/2
✓ Branch 0 taken 5590910 times.
✓ Branch 1 taken 336153 times.
5927063 if (trx_original_server_version == UNDEFINED_SERVER_VERSION) {
1751 /*
1752 When applying a transaction using replication, assume that the
1753 original server version is not known (the transaction wasn't
1754 originated on the current server).
1755 */
1756
6/6
✓ Branch 0 taken 5590757 times.
✓ Branch 1 taken 153 times.
✓ Branch 2 taken 40 times.
✓ Branch 3 taken 5590717 times.
✓ Branch 4 taken 193 times.
✓ Branch 5 taken 5590717 times.
5590910 if (thd->slave_thread || thd->is_binlog_applier()) {
1757 193 trx_original_server_version = UNKNOWN_SERVER_VERSION;
1758 } else
1759 /* Assume that this transaction is original from this server */
1760 {
1761 5590717 trx_original_server_version = trx_immediate_server_version;
1762 }
1763 } else {
1764 // Clear the session variable to have cleared states for next transaction.
1765 336153 thd->variables.original_server_version = UNDEFINED_SERVER_VERSION;
1766 }
1767 Gtid_log_event gtid_event(
1768 5927063 thd, cache_data->is_trx_cache(), last_committed, sequence_number,
1769 5927063 cache_data->may_have_sbr_stmts(), original_commit_timestamp,
1770 immediate_commit_timestamp, trx_original_server_version,
1771
1/2
✓ Branch 0 taken 5927063 times.
✗ Branch 1 not taken.
5927063 trx_immediate_server_version);
1772
1773 // Set the transaction length, based on cache info
1774
2/4
✓ Branch 0 taken 5927063 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5927063 times.
✗ Branch 3 not taken.
5927063 gtid_event.set_trx_length_by_cache_size(cache_data->get_byte_position(),
1775 5927063 writer->is_checksum_enabled(),
1776 5927063 cache_data->get_event_counter());
1777
1778
6/10
✓ Branch 0 taken 5927063 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5927063 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 103 times.
✓ Branch 5 taken 5926960 times.
✓ Branch 6 taken 103 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 103 times.
✗ Branch 9 not taken.
5927063 DBUG_PRINT("debug", ("cache_data->get_byte_position()= %llu",
1779 cache_data->get_byte_position()));
1780
5/8
✓ Branch 0 taken 5927063 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5927063 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 103 times.
✓ Branch 5 taken 5926960 times.
✓ Branch 6 taken 103 times.
✗ Branch 7 not taken.
5927063 DBUG_PRINT("debug", ("cache_data->get_event_counter()= %lu",
1781 static_cast<ulong>(cache_data->get_event_counter())));
1782
6/10
✓ Branch 0 taken 5927063 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5927063 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 103 times.
✓ Branch 5 taken 5926960 times.
✓ Branch 6 taken 103 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 103 times.
✗ Branch 9 not taken.
5927063 DBUG_PRINT("debug", ("writer->is_checksum_enabled()= %s",
1783 YESNO(writer->is_checksum_enabled())));
1784
6/10
✓ Branch 0 taken 5927063 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5927063 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 103 times.
✓ Branch 5 taken 5926960 times.
✓ Branch 6 taken 103 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 103 times.
✗ Branch 9 not taken.
5927063 DBUG_PRINT("debug", ("gtid_event.get_event_length()= %lu",
1785 static_cast<ulong>(gtid_event.get_event_length())));
1786
5/8
✓ Branch 0 taken 5927063 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5927063 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 106 times.
✓ Branch 5 taken 5926957 times.
✓ Branch 6 taken 106 times.
✗ Branch 7 not taken.
5927063 DBUG_PRINT("info",
1787 ("transaction_length= %llu", gtid_event.transaction_length));
1788
1789
1/2
✓ Branch 0 taken 5927063 times.
✗ Branch 1 not taken.
5927063 bool ret = gtid_event.write(writer);
1790
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5927063 times.
5927063 if (ret) goto end;
1791
1792 /*
1793 finally write the transaction data, if it was not compressed
1794 and written as part of the gtid event already
1795 */
1796
1/2
✓ Branch 0 taken 5927060 times.
✗ Branch 1 not taken.
5927063 ret = mysql_bin_log.write_cache(thd, cache_data, writer);
1797
1798
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 5927057 times.
5927060 if (!ret) {
1799 // update stats if monitoring is active
1800
1/2
✓ Branch 0 taken 5927057 times.
✗ Branch 1 not taken.
5927057 binlog::global_context.monitoring_context()
1801
1/2
✓ Branch 0 taken 5927057 times.
✗ Branch 1 not taken.
5927057 .transaction_compression()
1802
1/2
✓ Branch 0 taken 5927057 times.
✗ Branch 1 not taken.
11854114 .update(binlog::monitoring::log_type::BINARY,
1803 5927057 cache_data->get_compression_type(), thd->owned_gtid,
1804 5927057 gtid_event.immediate_commit_timestamp,
1805 cache_data->get_compressed_size(),
1806 cache_data->get_decompressed_size());
1807 }
1808
1809 3 end:
1810 5927060 return ret;
1811 5927060 }
1812
1813 1704587 int MYSQL_BIN_LOG::gtid_end_transaction(THD *thd) {
1814
1/2
✓ Branch 0 taken 1704895 times.
✗ Branch 1 not taken.
1704587 DBUG_TRACE;
1815
1816
5/10
✓ Branch 0 taken 1704887 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1704916 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 87 times.
✓ Branch 5 taken 1704829 times.
✓ Branch 6 taken 87 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
1704895 DBUG_PRINT("info", ("query=%s", thd->query().str));
1817
1818
2/2
✓ Branch 0 taken 50479 times.
✓ Branch 1 taken 1654139 times.
1704618 if (thd->owned_gtid.sidno > 0) {
1819
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 50479 times.
50479 assert(thd->variables.gtid_next.type == ASSIGNED_GTID);
1820
1821
5/6
✓ Branch 0 taken 50455 times.
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 20139 times.
✓ Branch 3 taken 30316 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 20139 times.
50479 if (!opt_bin_log || (thd->slave_thread && !opt_log_replica_updates)) {
1822 /*
1823 If the binary log is disabled for this thread (either by
1824 log_bin=0 or sql_log_bin=0 or by log_replica_updates=0 for a
1825 slave thread), then the statement must not be written to the
1826 binary log. In this case, we just save the GTID into the
1827 table directly.
1828
1829 (This only happens for DDL, since DML will save the GTID into
1830 table and release ownership inside ha_commit_trans.)
1831 */
1832
2/4
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 24 times.
24 if (gtid_state->save(thd) != 0) {
1833 gtid_state->update_on_rollback(thd);
1834 return 1;
1835
3/4
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 17 times.
24 } else if (!has_commit_order_manager(thd)) {
1836 /*
1837 The gtid_state->save implicitly performs the commit, in the following
1838 stack:
1839 Gtid_state::save ->
1840 Gtid_table_persistor::save ->
1841 Gtid_table_access_context::deinit ->
1842 System_table_access::close_table ->
1843 ha_commit_trans ->
1844 Relay_log_info::pre_commit ->
1845 Slave_worker::commit_positions(THD*) ->
1846 Slave_worker::commit_positions(THD*,Log_event*,...) ->
1847 Slave_worker::flush_info ->
1848 Rpl_info_handler::flush_info ->
1849 Rpl_info_table::do_flush_info ->
1850 Rpl_info_table_access::close_table ->
1851 System_table_access::close_table ->
1852 ha_commit_trans ->
1853 MYSQL_BIN_LOG::commit ->
1854 ha_commit_low
1855
1856 If replica-preserve-commit-order is disabled, it does not call
1857 update_on_commit from this stack. The reason is as follows:
1858
1859 In the normal case of MYSQL_BIN_LOG::commit, where the transaction is
1860 going to be written to the binary log, it invokes
1861 MYSQL_BIN_LOG::ordered_commit, which updates the GTID state (the call
1862 gtid_state->update_commit_group(first) in process_commit_stage_queue).
1863 However, when MYSQL_BIN_LOG::commit is invoked from this stack, it is
1864 because the transaction is not going to be written to the binary log,
1865 and then MYSQL_BIN_LOG::commit has a special case that calls
1866 ha_commit_low directly, skipping ordered_commit. Therefore, the GTID
1867 state is not updated in this stack.
1868
1869 On the other hand, if replica-preserve-commit-order is enabled, the
1870 logic that orders commit carries out a subset of the binlog group
1871 commit from within ha_commit_low, and this includes updating the GTID
1872 state. In particular, there is the following call stack under
1873 ha_commit_low:
1874
1875 ha_commit_low ->
1876 Commit_order_manager::wait_and_finish ->
1877 Commit_order_manager::finish ->
1878 Commit_order_manager::flush_engine_and_signal_threads ->
1879 Gtid_state::update_commit_group
1880
1881 Therefore, it is necessary to call update_on_commit only in case we
1882 are not using replica-preserve-commit-order here.
1883 */
1884
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 gtid_state->update_on_commit(thd);
1885 }
1886 } else {
1887 /*
1888 If statement is supposed to be written to binlog, we write it
1889 to the binary log. Inserting into table and releasing
1890 ownership will be done in the binlog commit handler.
1891 */
1892
1893 /*
1894 thd->cache_mngr may be uninitialized if the first transaction
1895 executed by the client is empty.
1896 */
1897
2/4
✓ Branch 0 taken 50455 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 50455 times.
50457 if (thd->binlog_setup_trx_data()) return 1;
1898
1/2
✓ Branch 0 taken 50455 times.
✗ Branch 1 not taken.
50455 binlog_cache_data *cache_data = &thd_get_cache_mngr(thd)->trx_cache;
1899
1900 // Generate BEGIN event
1901 Query_log_event qinfo(thd, STRING_WITH_LEN("BEGIN"), true, false, true, 0,
1902
1/2
✓ Branch 0 taken 50455 times.
✗ Branch 1 not taken.
50455 true);
1903
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 50455 times.
50455 assert(!qinfo.is_using_immediate_logging());
1904
1905 /*
1906 Write BEGIN event and then commit (which will generate commit
1907 event and Gtid_log_event)
1908 */
1909
3/8
✓ Branch 0 taken 50455 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 50455 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 50455 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
50455 DBUG_PRINT("debug", ("Writing to trx_cache"));
1910
7/10
✓ Branch 0 taken 50455 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 50455 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 50455 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 50453 times.
✓ Branch 8 taken 2 times.
✓ Branch 9 taken 50453 times.
50455 if (cache_data->write_event(&qinfo) || mysql_bin_log.commit(thd, true))
1911 2 return 1;
1912
2/2
✓ Branch 0 taken 50453 times.
✓ Branch 1 taken 2 times.
50455 }
1913
2/2
✓ Branch 0 taken 1588332 times.
✓ Branch 1 taken 65807 times.
1654139 } else if (thd->owned_gtid.sidno == THD::OWNED_SIDNO_ANONYMOUS ||
1914 /*
1915 A transaction with an empty owned gtid should call
1916 end_gtid_violating_transaction(...) to clear the
1917 flag thd->has_gtid_consistency_violatoin in case
1918 it is set. It missed the clear in ordered_commit,
1919 because its binlog transaction cache is empty.
1920 */
1921
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1588395 times.
1588332 thd->has_gtid_consistency_violation)
1922
1923 {
1924
1/2
✓ Branch 0 taken 65812 times.
✗ Branch 1 not taken.
65744 gtid_state->update_on_commit(thd);
1925
4/4
✓ Branch 0 taken 6548 times.
✓ Branch 1 taken 1581847 times.
✓ Branch 2 taken 6548 times.
✓ Branch 3 taken 1581847 times.
1594943 } else if (thd->variables.gtid_next.type == ASSIGNED_GTID &&
1926
2/4
✓ Branch 0 taken 6548 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6548 times.
✗ Branch 3 not taken.
6548 thd->owned_gtid_is_empty()) {
1927
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6548 times.
6548 assert(thd->has_gtid_consistency_violation == false);
1928
1/2
✓ Branch 0 taken 6574 times.
✗ Branch 1 not taken.
6548 gtid_state->update_on_commit(thd);
1929 }
1930
1931 1704710 return 0;
1932 1704712 }
1933
1934 77 bool MYSQL_BIN_LOG::reencrypt_logs() {
1935
1/2
✓ Branch 0 taken 77 times.
✗ Branch 1 not taken.
77 DBUG_TRACE;
1936
1937
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 77 times.
77 if (!is_open()) return false;
1938
1939 77 std::string error_message;
1940 /* Gather the set of files to be accessed. */
1941 77 list<string> filename_list;
1942 77 LOG_INFO linfo;
1943 77 int error = 0;
1944 77 list<string>::reverse_iterator rit;
1945
1946 /* Read binary/relay log file names from index file. */
1947
1/2
✓ Branch 0 taken 77 times.
✗ Branch 1 not taken.
77 mysql_mutex_lock(&LOCK_index);
1948
3/4
✓ Branch 0 taken 77 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1357 times.
✓ Branch 3 taken 77 times.
1434 for (error = find_log_pos(&linfo, nullptr, false); !error;
1949 1357 error = find_next_log(&linfo, false)) {
1950
3/6
✓ Branch 0 taken 1357 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1357 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1357 times.
✗ Branch 5 not taken.
1357 filename_list.push_back(string(linfo.log_file_name));
1951 }
1952
1/2
✓ Branch 0 taken 77 times.
✗ Branch 1 not taken.
77 mysql_mutex_unlock(&LOCK_index);
1953
3/4
✓ Branch 0 taken 77 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 75 times.
154 if (error != LOG_INFO_EOF ||
1954
3/4
✓ Branch 0 taken 77 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 75 times.
77 DBUG_EVALUATE_IF("fail_to_open_index_file", true, false)) {
1955
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 error_message.assign("I/O error reading index file '");
1956
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 error_message.append(index_file_name);
1957
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 error_message.append("'");
1958 2 goto err;
1959 }
1960
1961 75 rit = filename_list.rbegin();
1962 /* Skip the last binary/relay log. */
1963
3/6
✓ Branch 0 taken 75 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 75 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 75 times.
✗ Branch 5 not taken.
75 if (rit != filename_list.rend()) rit++;
1964 /* Iterate backwards through binary/relay logs. */
1965
3/4
✓ Branch 0 taken 1226 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1162 times.
✓ Branch 3 taken 64 times.
1226 while (rit != filename_list.rend()) {
1966
1/2
✓ Branch 0 taken 1162 times.
✗ Branch 1 not taken.
1162 const char *filename = rit->c_str();
1967
4/6
✓ Branch 0 taken 1162 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1161 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1162 DBUG_EXECUTE_IF("purge_logs_during_reencryption", {
1968 purge_logs(filename, true, true /*need_lock_index=true*/,
1969 true /*need_update_threads=true*/, nullptr, false);
1970 });
1971 1162 MUTEX_LOCK(lock, &LOCK_index);
1972 std::unique_ptr<Binlog_ofile> ofile(
1973
1/2
✓ Branch 0 taken 1162 times.
✗ Branch 1 not taken.
1162 Binlog_ofile::open_existing(key_file_binlog, filename, MYF(MY_WME)));
1974
1975 1162 if (ofile == nullptr ||
1976
7/8
✓ Branch 0 taken 1161 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1161 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1159 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 4 times.
✓ Branch 7 taken 1158 times.
2321 DBUG_EVALUATE_IF("fail_to_open_log_file", true, false) ||
1977
3/4
✓ Branch 0 taken 1159 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1158 times.
1159 DBUG_EVALUATE_IF("fail_to_read_index_file", true, false)) {
1978 /* If we can not open the log file, check if it exists in index file. */
1979
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 error = find_log_pos(&linfo, filename, false);
1980
3/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 3 times.
4 DBUG_EXECUTE_IF("fail_to_read_index_file", error = LOG_INFO_IO;);
1981
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
4 if (error == LOG_INFO_EOF) {
1982 /* If it does not exist in index file, re-encryption has finished. */
1983
5/10
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
1 if (current_thd->is_error()) current_thd->clear_error();
1984 1 break;
1985
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 } else if (error == 0) {
1986 /* If it exists in index file, failed to open the log file. */
1987
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 error_message.assign("Failed to open log file '");
1988
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 error_message.append(filename);
1989
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 error_message.append("'");
1990 2 goto err;
1991
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 } else if (error == LOG_INFO_IO) {
1992 /* Failed to read index file. */
1993
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 error_message.assign("I/O error reading index file '");
1994
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 error_message.append(index_file_name);
1995
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 error_message.append("'");
1996 1 goto err;
1997 }
1998 }
1999
2000
2/2
✓ Branch 0 taken 1070 times.
✓ Branch 1 taken 88 times.
1158 if (ofile->is_encrypted()) {
2001 std::unique_ptr<Truncatable_ostream> pipeline_head =
2002 1070 ofile->get_pipeline_head();
2003 std::unique_ptr<Binlog_encryption_ostream> binlog_encryption_ostream(
2004 1070 down_cast<Binlog_encryption_ostream *>(pipeline_head.release()));
2005
2006
1/2
✓ Branch 0 taken 1070 times.
✗ Branch 1 not taken.
1070 auto ret_value = binlog_encryption_ostream->reencrypt();
2007
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 1063 times.
1070 if (ret_value.first) {
2008
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 error_message.assign("Failed to re-encrypt log file '");
2009
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 error_message.append(filename);
2010
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 error_message.append("': ");
2011
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 error_message.append(ret_value.second.c_str());
2012 7 goto err;
2013 }
2014
6/6
✓ Branch 0 taken 1063 times.
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 1063 times.
✓ Branch 3 taken 7 times.
✓ Branch 4 taken 1063 times.
✓ Branch 5 taken 7 times.
1084 }
2015
2016
1/2
✓ Branch 0 taken 1151 times.
✗ Branch 1 not taken.
1151 rit++;
2017
6/6
✓ Branch 0 taken 1151 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 1151 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 10 times.
1173 }
2018
2019 65 filename_list.clear();
2020
2021 65 return false;
2022
2023 12 err:
2024
3/10
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 12 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
12 if (current_thd->is_error()) current_thd->clear_error();
2025
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 my_error(ER_BINLOG_MASTER_KEY_ROTATION_FAIL_TO_REENCRYPT_LOG, MYF(0),
2026 error_message.c_str());
2027 12 filename_list.clear();
2028
2029 12 return true;
2030 77 }
2031
2032 5927339 bool binlog_cache_data::compress(THD *thd) {
2033
1/2
✓ Branch 0 taken 5927698 times.
✗ Branch 1 not taken.
5927339 DBUG_TRACE;
2034 5927698 auto error{false};
2035 5927698 auto ctype{binary_log::transaction::compression::type::NONE};
2036
1/2
✓ Branch 0 taken 5927650 times.
✗ Branch 1 not taken.
5927698 auto uncompressed_size{m_cache.length()};
2037 5927650 auto size{uncompressed_size};
2038 5927650 auto &cctx{thd->rpl_thd_ctx.transaction_compression_ctx()};
2039 5927447 binary_log::transaction::compression::Compressor *compressor{nullptr};
2040
2041 // no compression enabled (ctype == NONE at this point)
2042
2/2
✓ Branch 0 taken 5927346 times.
✓ Branch 1 taken 101 times.
5927447 if (thd->variables.binlog_trx_compression == false) goto end;
2043
2044 // do not compress if there are incident events
2045
3/4
✓ Branch 0 taken 165 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 163 times.
101 DBUG_EXECUTE_IF("binlog_compression_inject_incident", set_incident(););
2046
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 163 times.
165 if (has_incident()) goto end;
2047
2048 // do not compress if there are non-transactional changes
2049 163 if (thd->get_transaction()->has_modified_non_trans_table(
2050
6/6
✓ Branch 0 taken 156 times.
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 155 times.
✓ Branch 4 taken 8 times.
✓ Branch 5 taken 155 times.
319 Transaction_ctx::STMT) ||
2051 156 thd->get_transaction()->has_modified_non_trans_table(
2052 Transaction_ctx::SESSION))
2053 8 goto end;
2054
2055 // do not compress if has SBR
2056
2/2
✓ Branch 0 taken 95 times.
✓ Branch 1 taken 60 times.
155 if (may_have_sbr_stmts()) goto end;
2057
2058 // Unable to get a reference to a compressor, fallback to
2059 // non compressed
2060
2/4
✓ Branch 0 taken 60 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 60 times.
60 if ((compressor = cctx.get_compressor(thd)) == nullptr) goto end;
2061
2062 // compression is enabled and all pre-conditions checked.
2063 // now compress
2064 else {
2065 60 std::size_t old_capacity{0};
2066 60 unsigned char *buffer{nullptr};
2067 60 unsigned char *old_buffer{nullptr};
2068
1/2
✓ Branch 0 taken 60 times.
✗ Branch 1 not taken.
60 Transaction_payload_log_event tple{thd};
2069
1/2
✓ Branch 0 taken 60 times.
✗ Branch 1 not taken.
60 Compressed_ostream stream;
2070 60 PSI_stage_info old_stage;
2071
2072 // set the thread stage to compressing transaction
2073
1/2
✓ Branch 0 taken 60 times.
✗ Branch 1 not taken.
60 thd->enter_stage(&stage_binlog_transaction_compress, &old_stage, __func__,
2074 __FILE__, __LINE__);
2075 // do we have enough compression buffer ? If not swap with a larger one
2076
2/4
✓ Branch 0 taken 60 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 60 times.
✗ Branch 3 not taken.
60 std::tie(buffer, std::ignore, old_capacity) = compressor->get_buffer();
2077
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 28 times.
60 if (old_capacity < size) {
2078 32 old_buffer = buffer;
2079 32 auto new_buffer = (unsigned char *)malloc(size);
2080
1/2
✓ Branch 0 taken 32 times.
✗ Branch 1 not taken.
32 if (new_buffer)
2081
1/2
✓ Branch 0 taken 32 times.
✗ Branch 1 not taken.
32 compressor->set_buffer(new_buffer, size);
2082 else {
2083 /* purecov: begin inspected */
2084 // OOM
2085 error = true;
2086 goto compression_end;
2087 /* purecov: end */
2088 }
2089 }
2090
2091
1/2
✓ Branch 0 taken 60 times.
✗ Branch 1 not taken.
60 ctype = compressor->compression_type_code();
2092
2093
1/2
✓ Branch 0 taken 60 times.
✗ Branch 1 not taken.
60 compressor->open();
2094
2095 // inject the compressor in the output stream
2096
1/2
✓ Branch 0 taken 60 times.
✗ Branch 1 not taken.
60 stream.set_compressor(compressor);
2097
2098 // FIXME: innefficient, we should not copy caches around
2099 // This should be fixed when we revamp the capture
2100 // cache handling (and make this more geared towards
2101 // possible enhancements, such as streaming the changes)
2102 // Also, if the cache actually spills to disk, this may
2103 // the impact may be amplified, since reiniting the
2104 // causes a flush to disk
2105
2/4
✓ Branch 0 taken 60 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 60 times.
60 if ((error = m_cache.copy_to(&stream))) goto compression_end;
2106
2107
1/2
✓ Branch 0 taken 60 times.
✗ Branch 1 not taken.
60 compressor->close();
2108
2109
2/4
✓ Branch 0 taken 60 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 60 times.
60 if ((error = m_cache.truncate(0))) goto compression_end;
2110 // Since we deleted all events from the cache, we also need to
2111 // reset event_counter.
2112 60 event_counter = 0;
2113
2114 // fill in the new transport event
2115
2/4
✓ Branch 0 taken 60 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 60 times.
✗ Branch 3 not taken.
60 std::tie(buffer, size, std::ignore) = compressor->get_buffer();
2116 60 tple.set_payload((const char *)buffer);
2117 60 tple.set_payload_size(size);
2118 60 tple.set_compression_type(ctype);
2119 60 tple.set_uncompressed_size(uncompressed_size);
2120
2121 // write back the new cache contents
2122
1/2
✓ Branch 0 taken 60 times.
✗ Branch 1 not taken.
60 error = write_event(&tple);
2123
2124 60 compression_end:
2125 // revert back to the default buffer, so that we don't overuse memory
2126
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 28 times.
60 if (old_buffer) {
2127
2/4
✓ Branch 0 taken 32 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 32 times.
✗ Branch 3 not taken.
32 std::tie(buffer, std::ignore, std::ignore) = compressor->get_buffer();
2128
1/2
✓ Branch 0 taken 32 times.
✗ Branch 1 not taken.
32 compressor->set_buffer(old_buffer, old_capacity);
2129 32 free(buffer);
2130 }
2131
2132 // revert the stage if needed
2133
2/4
✓ Branch 0 taken 60 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 60 times.
✗ Branch 3 not taken.
60 if (old_stage.m_key != 0) THD_STAGE_INFO(thd, old_stage);
2134 60 }
2135
2136 5927511 end:
2137
2/2
✓ Branch 0 taken 5927340 times.
✓ Branch 1 taken 171 times.
5927511 if (!error) {
2138 5927340 set_compression_type(ctype);
2139
1/2
✓ Branch 0 taken 5927517 times.
✗ Branch 1 not taken.
5927359 set_compressed_size(m_cache.length());
2140 5927425 set_decompressed_size(uncompressed_size);
2141 }
2142 5927755 return error;
2143 5927686 }
2144
2145 /**
2146 This function finalizes the cache preparing for commit or rollback.
2147
2148 The function just writes all the necessary events to the cache but
2149 does not flush the data to the binary log file. That is the role of
2150 the binlog_cache_data::flush function.
2151
2152 @see binlog_cache_data::flush
2153
2154 @param thd The thread whose transaction should be flushed
2155 @param end_event The end event either commit/rollback
2156
2157 @return
2158 nonzero if an error pops up when flushing the cache.
2159 */
2160 5927087 int binlog_cache_data::finalize(THD *thd, Log_event *end_event) {
2161
1/2
✓ Branch 0 taken 5927621 times.
✗ Branch 1 not taken.
5927087 DBUG_TRACE;
2162
2/4
✓ Branch 0 taken 5927631 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5927639 times.
✗ Branch 3 not taken.
5927621 if (!is_binlog_empty()) {
2163
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5927639 times.
5927639 assert(!flags.finalized);
2164
2/4
✓ Branch 0 taken 5927084 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5927084 times.
5927639 if (int error = flush_pending_event(thd)) return error;
2165
2/4
✓ Branch 0 taken 5927754 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5927754 times.
5927084 if (int error = write_event(end_event)) return error;
2166
2/4
✓ Branch 0 taken 5927759 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5927759 times.
5927754 if (int error = this->compress(thd)) return error;
2167
6/10
✓ Branch 0 taken 5927609 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5927581 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 103 times.
✓ Branch 5 taken 5927478 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 103 times.
✓ Branch 8 taken 129 times.
✗ Branch 9 not taken.
5927759 DBUG_PRINT("debug", ("flags.finalized: %s", YESNO(flags.finalized)));
2168 5927607 flags.finalized = true;
2169 }
2170 5927599 return 0;
2171 5927599 }
2172
2173 /**
2174 The method writes XA END query to XA-prepared transaction's cache
2175 and calls the "basic" finalize().
2176
2177 @return error code, 0 success
2178 */
2179
2180 634 int binlog_cache_data::finalize(THD *thd, Log_event *end_event, XID_STATE *xs) {
2181 634 int error = 0;
2182 char buf[XID::ser_buf_size];
2183 char query[sizeof("XA END") + 1 + sizeof(buf)];
2184 634 int qlen = sprintf(query, "XA END %s", xs->get_xid()->serialize(buf));
2185
1/2
✓ Branch 0 taken 634 times.
✗ Branch 1 not taken.
634 Query_log_event qev(thd, query, qlen, true, false, true, 0);
2186
2187
2/4
✓ Branch 0 taken 634 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 634 times.
634 if ((error = write_event(&qev))) return error;
2188
2189
1/2
✓ Branch 0 taken 634 times.
✗ Branch 1 not taken.
634 return finalize(thd, end_event);
2190 634 }
2191
2192 /**
2193 Flush caches to the binary log.
2194
2195 If the cache is finalized, the cache will be flushed to the binary
2196 log file. If the cache is not finalized, nothing will be done.
2197
2198 If flushing fails for any reason, an error will be reported and the
2199 cache will be reset. Flushing can fail in two circumstances:
2200
2201 - It was not possible to write the cache to the file. In this case,
2202 it does not make sense to keep the cache.
2203
2204 - The cache was successfully written to disk but post-flush actions
2205 (such as binary log rotation) failed. In this case, the cache is
2206 already written to disk and there is no reason to keep it.
2207
2208 @see binlog_cache_data::finalize
2209 */
2210 11852832 int binlog_cache_data::flush(THD *thd, my_off_t *bytes_written,
2211 bool *wrote_xid) {
2212 /*
2213 Doing a commit or a rollback including non-transactional tables,
2214 i.e., ending a transaction where we might write the transaction
2215 cache to the binary log.
2216
2217 We can always end the statement when ending a transaction since
2218 transactions are not allowed inside stored functions. If they
2219 were, we would have to ensure that we're not ending a statement
2220 inside a stored function.
2221 */
2222
1/2
✓ Branch 0 taken 11852832 times.
✗ Branch 1 not taken.
11852832 DBUG_TRACE;
2223
7/10
✓ Branch 0 taken 11852832 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11852832 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 205 times.
✓ Branch 5 taken 11852627 times.
✓ Branch 6 taken 103 times.
✓ Branch 7 taken 102 times.
✓ Branch 8 taken 205 times.
✗ Branch 9 not taken.
11852832 DBUG_PRINT("debug", ("flags.finalized: %s", YESNO(flags.finalized)));
2224 11852832 int error = 0;
2225
2/2
✓ Branch 0 taken 5927064 times.
✓ Branch 1 taken 5925768 times.
11852832 if (flags.finalized) {
2226
1/2
✓ Branch 0 taken 5927064 times.
✗ Branch 1 not taken.
5927064 my_off_t bytes_in_cache = m_cache.length();
2227 5927064 Transaction_ctx *trn_ctx = thd->get_transaction();
2228
2229
5/8
✓ Branch 0 taken 5927064 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5927064 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 103 times.
✓ Branch 5 taken 5926961 times.
✓ Branch 6 taken 103 times.
✗ Branch 7 not taken.
5927064 DBUG_PRINT("debug", ("bytes_in_cache: %llu", bytes_in_cache));
2230
2231
1/2
✓ Branch 0 taken 5927064 times.
✗ Branch 1 not taken.
5927064 trn_ctx->sequence_number = mysql_bin_log.m_dependency_tracker.step();
2232
2233 /*
2234 In case of two caches the transaction is split into two groups.
2235 The 2nd group is considered to be a successor of the 1st rather
2236 than to have a common commit parent with it.
2237 Notice that due to a simple method of detection that the current is
2238 the 2nd cache being flushed, the very first few transactions may be logged
2239 sequentially (a next one is tagged as if a preceding one is its
2240 commit parent).
2241 */
2242
2/2
✓ Branch 0 taken 67942 times.
✓ Branch 1 taken 5859122 times.
5927064 if (trn_ctx->last_committed == SEQ_UNINIT)
2243 67942 trn_ctx->last_committed = trn_ctx->sequence_number - 1;
2244
2245 /*
2246 The GTID is written prior to flushing the statement cache, if
2247 the transaction has written to the statement cache; and prior to
2248 flushing the transaction cache if the transaction has written to
2249 the transaction cache. If GTIDs are enabled, then transactional
2250 and non-transactional updates cannot be mixed, so at most one of
2251 the caches can be non-empty, so just one GTID will be
2252 generated. If GTIDs are disabled, then no GTID is generated at
2253 all; if both the transactional cache and the statement cache are
2254 non-empty then we get two Anonymous_gtid_log_events, which is
2255 correct.
2256 */
2257
1/2
✓ Branch 0 taken 5927064 times.
✗ Branch 1 not taken.
5927064 Binlog_event_writer writer(mysql_bin_log.get_binlog_file(), thd);
2258
2259 /* The GTID ownership process might set the commit_error */
2260
1/2
✓ Branch 0 taken 5927064 times.
✗ Branch 1 not taken.
11854128 error = (thd->commit_error == THD::CE_FLUSH_ERROR ||
2261
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 5927063 times.
5927064 thd->commit_error == THD::CE_FLUSH_GNO_EXHAUSTED_ERROR);
2262
2263
5/6
✓ Branch 0 taken 5927064 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 29940 times.
✓ Branch 3 taken 5897124 times.
✓ Branch 4 taken 9886 times.
✓ Branch 5 taken 20054 times.
5927064 DBUG_EXECUTE_IF("simulate_binlog_flush_error", {
2264 if (rand() % 3 == 0) {
2265 thd->commit_error = THD::CE_FLUSH_ERROR;
2266 }
2267 };);
2268
2269
4/6
✓ Branch 0 taken 5927064 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 5927063 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
5927064 DBUG_EXECUTE_IF("fault_injection_reinit_io_cache_while_flushing_to_file",
2270 { DBUG_SET("+d,fault_injection_reinit_io_cache"); });
2271
2272
2/2
✓ Branch 0 taken 5927063 times.
✓ Branch 1 taken 1 times.
5927064 if (!error)
2273
3/4
✓ Branch 0 taken 5927060 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 5927057 times.
5927063 if ((error = mysql_bin_log.write_transaction(thd, this, &writer)))
2274 3 thd->commit_error = THD::CE_FLUSH_ERROR;
2275
2276
4/6
✓ Branch 0 taken 5927061 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 5927060 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
5927061 DBUG_EXECUTE_IF("fault_injection_reinit_io_cache_while_flushing_to_file",
2277 { DBUG_SET("-d,fault_injection_reinit_io_cache"); });
2278
2279
4/4
✓ Branch 0 taken 5385685 times.
✓ Branch 1 taken 541376 times.
✓ Branch 2 taken 5385682 times.
✓ Branch 3 taken 3 times.
5927061 if (flags.with_xid && error == 0) *wrote_xid = true;
2280
2281 /*
2282 Reset have to be after the if above, since it clears the
2283 with_xid flag
2284 */
2285
1/2
✓ Branch 0 taken 5927061 times.
✗ Branch 1 not taken.
5927061 reset();
2286
1/2
✓ Branch 0 taken 5927061 times.
✗ Branch 1 not taken.
5927061 if (bytes_written) *bytes_written = bytes_in_cache;
2287 5927061 }
2288
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11852829 times.
11852829 assert(!flags.finalized);
2289 11852829 return error;
2290 11852829 }
2291
2292 /**
2293 This function truncates the transactional cache upon committing or rolling
2294 back either a transaction or a statement.
2295
2296 @param thd The thread whose transaction should be flushed
2297 @param all @c true means truncate the transaction, otherwise the
2298 statement must be truncated.
2299
2300 @return
2301 nonzero if an error pops up when truncating the transactional cache.
2302 */
2303 8030 int binlog_trx_cache_data::truncate(THD *thd, bool all) {
2304
1/2
✓ Branch 0 taken 8031 times.
✗ Branch 1 not taken.
8030 DBUG_TRACE;
2305 8031 int error = 0;
2306
2307
8/14
✓ Branch 0 taken 8031 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8031 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 8030 times.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 times.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 times.
✗ Branch 13 not taken.
8031 DBUG_PRINT("info",
2308 ("thd->options={ %s %s}, transaction: %s",
2309 FLAGSTR(thd->variables.option_bits, OPTION_NOT_AUTOCOMMIT),
2310 FLAGSTR(thd->variables.option_bits, OPTION_BEGIN),
2311 all ? "all" : "stmt"));
2312
2313
1/2
✓ Branch 0 taken 8030 times.
✗ Branch 1 not taken.
8031 remove_pending_event();
2314
2315 /*
2316 If rolling back an entire transaction or a single statement not
2317 inside a transaction, we reset the transaction cache.
2318 Even though formally the atomic DDL statement may not end multi-statement
2319 transaction the cache needs full resetting as there must
2320 be no other data in it but belonging to the DDL.
2321 */
2322
3/4
✓ Branch 0 taken 8031 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4127 times.
✓ Branch 3 taken 3904 times.
8030 if (ending_trans(thd, all)) {
2323
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 4125 times.
4127 if (has_incident()) {
2324 2 const char *err_msg =
2325 "Error happend while resetting the transaction "
2326 "cache for a rolled back transaction or a single "
2327 "statement not inside a transaction.";
2328
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 error = mysql_bin_log.write_incident(thd, true /*need_lock_log=true*/,
2329 err_msg);
2330 }
2331
1/2
✓ Branch 0 taken 4127 times.
✗ Branch 1 not taken.
4127 reset();
2332 }
2333 /*
2334 If rolling back a statement in a transaction, we truncate the
2335 transaction cache to remove the statement.
2336 */
2337
2/2
✓ Branch 0 taken 732 times.
✓ Branch 1 taken 3171 times.
3904 else if (get_prev_position() != MY_OFF_T_UNDEF)
2338
1/2
✓ Branch 0 taken 732 times.
✗ Branch 1 not taken.
732 restore_prev_position();
2339
2340 8030 thd->clear_binlog_table_maps();
2341
2342 8031 return error;
2343 8030 }
2344
2345 5446711 inline enum xa_option_words get_xa_opt(THD *thd) {
2346 5446711 enum xa_option_words xa_opt = XA_NONE;
2347
2/2
✓ Branch 0 taken 1183 times.
✓ Branch 1 taken 5445528 times.
5446711 switch (thd->lex->sql_command) {
2348 1183 case SQLCOM_XA_COMMIT:
2349 xa_opt =
2350 1183 static_cast<Sql_cmd_xa_commit *>(thd->lex->m_sql_cmd)->get_xa_opt();
2351 1183 break;
2352 5445528 default:
2353 5445528 break;
2354 }
2355
2356 5446711 return xa_opt;
2357 }
2358
2359 /**
2360 Predicate function yields true when XA transaction is
2361 being logged having a proper state ready for prepare or
2362 commit in one phase.
2363
2364 @param thd THD pointer of running transaction
2365 @return true When the being prepared transaction should be binlogged,
2366 false otherwise.
2367 */
2368
2369 50842059 inline bool is_loggable_xa_prepare(THD *thd) {
2370 /*
2371 simulate_commit_failure is doing a trick with XID_STATE while
2372 the ongoing transaction is not XA, and therefore to be errored out,
2373 asserted below. In that case because of the
2374 latter fact the function returns @c false.
2375 */
2376
1/8
✗ Branch 0 not taken.
✓ Branch 1 taken 50843301 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
50842059 DBUG_EXECUTE_IF("simulate_commit_failure", {
2377 XID_STATE *xs = thd->get_transaction()->xid_state();
2378 assert((thd->is_error() && xs->get_state() == XID_STATE::XA_IDLE) ||
2379 xs->get_state() == XID_STATE::XA_NOTR);
2380 });
2381
2382
3/4
✓ Branch 0 taken 50843776 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2464 times.
✓ Branch 3 taken 50841721 times.
50843301 return DBUG_EVALUATE_IF(
2383 "simulate_commit_failure", false,
2384 thd->get_transaction()->xid_state()->has_state(XID_STATE::XA_IDLE));
2385 }
2386
2387 11110320 static int binlog_prepare(handlerton *, THD *thd, bool all) {
2388
1/2
✓ Branch 0 taken 11110947 times.
✗ Branch 1 not taken.
11110320 DBUG_TRACE;
2389
2/2
✓ Branch 0 taken 10610746 times.
✓ Branch 1 taken 500201 times.
11110947 if (!all) {
2390
1/2
✓ Branch 0 taken 10610785 times.
✗ Branch 1 not taken.
10610746 thd->get_transaction()->store_commit_parent(
2391 mysql_bin_log.m_dependency_tracker.get_max_committed_timestamp());
2392 }
2393 11111020 return 0;
2394 11110649 }
2395
2396 527 static int binlog_set_prepared_in_tc(handlerton *, THD *) { return 0; }
2397
2398 /**
2399 Logging XA commit/rollback of a prepared transaction in the case
2400 it was disconnected and resumed (recovered), or executed by a slave applier.
2401
2402 @param thd THD handle
2403 @param xid a pointer to XID object
2404 @param commit when @c true XA-COMMIT is logged, otherwise XA-ROLLBACK
2405
2406 @return error code, 0 success
2407 */
2408 1320 int MYSQL_BIN_LOG::write_xa_to_cache(THD *thd) {
2409
3/4
✓ Branch 0 taken 238 times.
✓ Branch 1 taken 1082 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 238 times.
1320 assert(thd->lex->sql_command == SQLCOM_XA_COMMIT ||
2410 thd->lex->sql_command == SQLCOM_XA_ROLLBACK);
2411
2412
3/4
✓ Branch 0 taken 1320 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 194 times.
✓ Branch 3 taken 1126 times.
1320 if (get_xa_opt(thd) == XA_ONE_PHASE) return 0;
2413
2414 1126 auto xid_state = thd->get_transaction()->xid_state();
2415
2/2
✓ Branch 0 taken 569 times.
✓ Branch 1 taken 557 times.
1126 if (!xid_state->is_binlogged())
2416 569 return 0; // nothing was really logged at prepare
2417
2418
7/10
✓ Branch 0 taken 557 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 555 times.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2 times.
✓ Branch 9 taken 555 times.
557 if (thd->is_error() && DBUG_EVALUATE_IF("simulate_xa_rm_error", 0, 1))
2419 2 return 0; // don't binlog if there are some errors.
2420
2421 555 auto xid_to_write = xid_state->get_xid();
2422
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 555 times.
555 assert(xid_to_write != nullptr);
2423
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 555 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
555 assert(!xid_to_write->is_null() ||
2424 !(thd->variables.option_bits & OPTION_BIN_LOG));
2425
2426
1/2
✓ Branch 0 taken 555 times.
✗ Branch 1 not taken.
555 std::ostringstream oss;
2427 oss << "XA "
2428 555 << (thd->lex->sql_command == SQLCOM_XA_COMMIT ? "COMMIT" : "ROLLBACK")
2429
7/12
✓ Branch 0 taken 555 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 410 times.
✓ Branch 3 taken 145 times.
✓ Branch 4 taken 555 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 555 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 555 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 555 times.
✗ Branch 11 not taken.
555 << " " << *xid_to_write << std::flush;
2430
1/2
✓ Branch 0 taken 555 times.
✗ Branch 1 not taken.
555 auto query = oss.str();
2431 555 Query_log_event qinfo(thd, query.data(), query.length(), false, true, true, 0,
2432
1/2
✓ Branch 0 taken 555 times.
✗ Branch 1 not taken.
1110 false);
2433
1/2
✓ Branch 0 taken 555 times.
✗ Branch 1 not taken.
555 return this->write_event(&qinfo);
2434 555 }
2435
2436 112 static int binlog_start_consistent_snapshot(handlerton *hton, THD *thd) {
2437
1/2
✓ Branch 0 taken 112 times.
✗ Branch 1 not taken.
112 DBUG_ENTER("binlog_start_consistent_snapshot");
2438
2439
1/2
✓ Branch 0 taken 112 times.
✗ Branch 1 not taken.
112 int err = thd->binlog_setup_trx_data();
2440
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 112 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
112 if (err) DBUG_RETURN(err);
2441
2442
1/2
✓ Branch 0 taken 112 times.
✗ Branch 1 not taken.
112 binlog_cache_mngr *const cache_mngr = thd_get_cache_mngr(thd);
2443
2444 /* Server layer calls us with LOCK_log locked, so this is safe. */
2445
1/2
✓ Branch 0 taken 112 times.
✗ Branch 1 not taken.
112 mysql_bin_log.raw_get_current_log(&cache_mngr->binlog_info);
2446
1/2
✓ Branch 0 taken 112 times.
✗ Branch 1 not taken.
112 gtid_state->get_snapshot_gtid_executed(cache_mngr->snapshot_gtid_executed);
2447
2448
1/2
✓ Branch 0 taken 112 times.
✗ Branch 1 not taken.
112 trans_register_ha(thd, true, hton, nullptr);
2449
2450
1/2
✓ Branch 0 taken 112 times.
✗ Branch 1 not taken.
112 DBUG_RETURN(err);
2451 }
2452
2453 21 static int binlog_clone_consistent_snapshot(handlerton *hton, THD *thd,
2454 THD *from_thd) {
2455
1/2
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
21 DBUG_ENTER("binlog_start_consistent_snapshot");
2456
2457 const binlog_cache_mngr *from_cache_mngr =
2458 opt_bin_log
2459
2/4
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 21 times.
✗ Branch 3 not taken.
21 ? static_cast<binlog_cache_mngr *>(thd_get_cache_mngr(from_thd))
2460 21 : nullptr;
2461
2462
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
21 if (from_cache_mngr == nullptr) {
2463 push_warning_printf(thd, Sql_condition::SL_WARNING, HA_ERR_UNSUPPORTED,
2464 "WITH CONSISTENT SNAPSHOT FROM SESSION was ignored for "
2465 "binary log, because the specified session does not "
2466 "have a consistent snapshot of binary log "
2467 "coordinates.");
2468 DBUG_RETURN(0);
2469 }
2470
2471
1/2
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
21 int err = thd->binlog_setup_trx_data();
2472
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
21 if (err) DBUG_RETURN(err);
2473
2474
1/2
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
21 binlog_cache_mngr *const cache_mngr = thd_get_cache_mngr(thd);
2475
2476 21 const my_off_t pos = from_cache_mngr->binlog_info.pos;
2477 char log_file_name[FN_REFLEN];
2478
1/2
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
21 strmake(log_file_name, from_cache_mngr->binlog_info.log_file_name,
2479 sizeof(log_file_name) - 1);
2480
2481
1/2
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
21 mysql_mutex_lock(&thd->LOCK_thd_data);
2482
2483
1/2
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
21 cache_mngr->snapshot_gtid_executed = from_cache_mngr->snapshot_gtid_executed;
2484 21 cache_mngr->binlog_info.pos = pos;
2485
1/2
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
21 strmake(cache_mngr->binlog_info.log_file_name, log_file_name,
2486 sizeof(cache_mngr->binlog_info.log_file_name) - 1);
2487
2488
1/2
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
21 mysql_mutex_unlock(&thd->LOCK_thd_data);
2489
2490
1/2
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
21 trans_register_ha(thd, true, hton, nullptr);
2491
2492
1/2
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
21 DBUG_RETURN(err);
2493 }
2494
2495 /**
2496 When a fatal error occurs due to which binary logging becomes impossible and
2497 the user specified binlog_error_action= ABORT_SERVER the following function is
2498 invoked. This function pushes the appropriate error message to client and logs
2499 the same to server error log and then aborts the server.
2500
2501 @param err_string Error string which specifies the exact error
2502 message from the caller.
2503 */
2504 static void exec_binlog_error_action_abort(const char *err_string) {
2505 THD *thd = current_thd;
2506 /*
2507 When the code enters here it means that there was an error at higher layer
2508 and my_error function could have been invoked to let the client know what
2509 went wrong during the execution.
2510
2511 But these errors will not let the client know that the server is going to
2512 abort. Even if we add an additional my_error function call at this point
2513 client will be able to see only the first error message that was set
2514 during the very first invocation of my_error function call.
2515
2516 The advantage of having multiple my_error function calls are visible when
2517 the server is up and running and user issues SHOW WARNINGS or SHOW ERROR
2518 calls. In this special scenario server will be immediately aborted and
2519 user will not be able execute the above SHOW commands.
2520
2521 Hence we clear the previous errors and push one critical error message to
2522 clients.
2523 */
2524 if (thd) {
2525 if (thd->is_error()) thd->clear_error();
2526 /*
2527 Send error to both client and to the server error log.
2528 */
2529 my_error(ER_BINLOG_LOGGING_IMPOSSIBLE, MYF(ME_FATALERROR), err_string);
2530 }
2531
2532 LogErr(ERROR_LEVEL, ER_BINLOG_LOGGING_NOT_POSSIBLE, err_string);
2533 flush_error_log_messages();
2534
2535 if (thd) thd->send_statement_status();
2536 my_abort();
2537 }
2538
2539 /**
2540 This function is called once after each statement.
2541
2542 @todo This function is currently not used any more and will
2543 eventually be eliminated. The real commit job is done in the
2544 MYSQL_BIN_LOG::commit function.
2545
2546 @see MYSQL_BIN_LOG::commit
2547
2548 @see handlerton::commit
2549 */
2550 11585739 static int binlog_commit(handlerton *, THD *, bool) {
2551
1/2
✓ Branch 0 taken 11585870 times.
✗ Branch 1 not taken.
11585739 DBUG_TRACE;
2552 /*
2553 Nothing to do (any more) on commit.
2554 */
2555 11585888 return 0;
2556 11585870 }
2557
2558 /**
2559 This function is called when a transaction or a statement is rolled back.
2560
2561 @internal It is necessary to execute a rollback here if the
2562 transaction was rolled back because of executing a ROLLBACK TO
2563 SAVEPOINT command, but it is not used for normal rollback since
2564 MYSQL_BIN_LOG::rollback is called in that case.
2565
2566 @todo Refactor code to introduce a <code>MYSQL_BIN_LOG::rollback(THD
2567 *thd, SAVEPOINT *sv)</code> function in @c TC_LOG and have that
2568 function execute the necessary work to rollback to a savepoint.
2569
2570 @param thd The client thread that executes the transaction.
2571 @param all This is @c true if this is a real transaction rollback, and
2572 @false otherwise.
2573
2574 @see handlerton::rollback
2575 */
2576 6705 static int binlog_rollback(handlerton *, THD *thd, bool all) {
2577
1/2
✓ Branch 0 taken 6705 times.
✗ Branch 1 not taken.
6705 DBUG_TRACE;
2578 6705 int error = 0;
2579
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 6673 times.
6705 if (thd->lex->sql_command == SQLCOM_ROLLBACK_TO_SAVEPOINT)
2580
1/2
✓ Branch 0 taken 32 times.
✗ Branch 1 not taken.
32 error = mysql_bin_log.rollback(thd, all);
2581 6705 return error;
2582 6705 }
2583
2584 /**
2585 Write a rollback record of the transaction to the binary log.
2586
2587 For binary log group commit, the rollback is separated into three
2588 parts:
2589
2590 1. First part consists of filling the necessary caches and
2591 finalizing them (if they need to be finalized). After a cache is
2592 finalized, nothing can be added to the cache.
2593
2594 2. Second part execute an ordered flush and commit. This will be
2595 done using the group commit functionality in @c ordered_commit.
2596
2597 Since we roll back the transaction early, we call @c
2598 ordered_commit with the @c skip_commit flag set. The @c
2599 ha_commit_low call inside @c ordered_commit will then not be
2600 called.
2601
2602 3. Third part checks any errors resulting from the flush and handles
2603 them appropriately.
2604
2605 @see MYSQL_BIN_LOG::ordered_commit
2606 @see ha_commit_low
2607 @see ha_rollback_low
2608
2609 @param thd Session to commit
2610 @param all This is @c true if this is a real transaction rollback, and
2611 @c false otherwise.
2612
2613 @return Error code, or zero if there were no error.
2614 */
2615
2616 2017694 int MYSQL_BIN_LOG::rollback(THD *thd, bool all) {
2617 2017694 int error = 0;
2618 2017694 bool stuff_logged = false;
2619
1/2
✓ Branch 0 taken 2018411 times.
✗ Branch 1 not taken.
2017694 binlog_cache_mngr *cache_mngr = thd_get_cache_mngr(thd);
2620 2018411 bool is_empty = false;
2621
2622
1/2
✓ Branch 0 taken 2018639 times.
✗ Branch 1 not taken.
2018411 DBUG_TRACE;
2623
10/14
✓ Branch 0 taken 2018554 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2018552 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 2018547 times.
✓ Branch 6 taken 5 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 4 times.
✓ Branch 9 taken 1 times.
✓ Branch 10 taken 2 times.
✓ Branch 11 taken 3 times.
✓ Branch 12 taken 5 times.
✗ Branch 13 not taken.
2018639 DBUG_PRINT("enter",
2624 ("all: %s, cache_mngr: 0x%llx, thd->is_error: %s", YESNO(all),
2625 (ulonglong)cache_mngr, YESNO(thd->is_error())));
2626 /*
2627 Defer XA-transaction rollback until its XA-rollback event is recorded.
2628 When we are executing a ROLLBACK TO SAVEPOINT, we
2629 should only clear the caches since this function is called as part
2630 of the engine rollback.
2631 In other cases we roll back the transaction in the engines early
2632 since this will release locks and allow other transactions to
2633 start executing.
2634 */
2635
3/4
✓ Branch 0 taken 2017903 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 238 times.
✓ Branch 3 taken 2017665 times.
2018552 if (is_xa_rollback(thd)) {
2636 238 auto xs = thd->get_transaction()->xid_state();
2637
2638
7/10
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 211 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 25 times.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
238 assert(all || !xs->is_binlogged() ||
2639 (!xs->is_detached() && thd->is_error()));
2640
2641 238 is_empty = !xs->is_binlogged();
2642
2643
2/4
✓ Branch 0 taken 238 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 238 times.
238 if ((error = this->write_xa_to_cache(thd)) != 0) goto end;
2644
2645
1/2
✓ Branch 0 taken 238 times.
✗ Branch 1 not taken.
238 cache_mngr = thd_get_cache_mngr(thd);
2646
2/2
✓ Branch 0 taken 2017424 times.
✓ Branch 1 taken 241 times.
2017665 } else if (thd->lex->sql_command != SQLCOM_ROLLBACK_TO_SAVEPOINT) {
2647 /*
2648 Reset binlog_snapshot_% variables for the current connection so that the
2649 current coordinates are shown after committing a consistent snapshot
2650 transaction.
2651 */
2652
2/2
✓ Branch 0 taken 210410 times.
✓ Branch 1 taken 1807014 times.
2017424 if (cache_mngr != nullptr) {
2653
1/2
✓ Branch 0 taken 210452 times.
✗ Branch 1 not taken.
210410 mysql_mutex_lock(&thd->LOCK_thd_data);
2654 210452 cache_mngr->drop_consistent_snapshot();
2655
1/2
✓ Branch 0 taken 210490 times.
✗ Branch 1 not taken.
210459 mysql_mutex_unlock(&thd->LOCK_thd_data);
2656 }
2657
2/4
✓ Branch 0 taken 2017343 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2017343 times.
2017504 if ((error = trx_coordinator::rollback_in_engines(thd, all))) goto end;
2658 }
2659
2660 /*
2661 If there is no cache manager, or if there is nothing in the
2662 caches, there are no caches to roll back, so we're trivially done
2663 unless XA-ROLLBACK that yet to run rollback_low().
2664 */
2665
7/8
✓ Branch 0 taken 210689 times.
✓ Branch 1 taken 1807133 times.
✓ Branch 2 taken 210763 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 202063 times.
✓ Branch 5 taken 8700 times.
✓ Branch 6 taken 2009154 times.
✓ Branch 7 taken 8742 times.
2017822 if (cache_mngr == nullptr || cache_mngr->is_binlog_empty()) {
2666 2009154 goto end;
2667 }
2668
2669
8/14
✓ Branch 0 taken 8700 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8700 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 8699 times.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 1 times.
✓ Branch 12 taken 1 times.
✗ Branch 13 not taken.
8742 DBUG_PRINT("debug", ("all.cannot_safely_rollback(): %s, trx_cache_empty: %s",
2670 YESNO(thd->get_transaction()->cannot_safely_rollback(
2671 Transaction_ctx::SESSION)),
2672 YESNO(cache_mngr->trx_cache.is_binlog_empty())));
2673
8/14
✓ Branch 0 taken 8700 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8700 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 8699 times.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 1 times.
✓ Branch 12 taken 1 times.
✗ Branch 13 not taken.
8700 DBUG_PRINT("debug",
2674 ("stmt.cannot_safely_rollback(): %s, stmt_cache_empty: %s",
2675 YESNO(thd->get_transaction()->cannot_safely_rollback(
2676 Transaction_ctx::STMT)),
2677 YESNO(cache_mngr->stmt_cache.is_binlog_empty())));
2678
2679 /*
2680 If an incident event is set we do not flush the content of the statement
2681 cache because it may be corrupted.
2682 */
2683
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 8693 times.
8700 if (cache_mngr->stmt_cache.has_incident()) {
2684 7 const char *err_msg =
2685 "The content of the statement cache is corrupted "
2686 "while writing a rollback record of the transaction "
2687 "to the binary log.";
2688
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 error = write_incident(thd, true /*need_lock_log=true*/, err_msg);
2689
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 cache_mngr->stmt_cache.reset();
2690
3/4
✓ Branch 0 taken 8693 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 838 times.
✓ Branch 3 taken 7855 times.
8693 } else if (!cache_mngr->stmt_cache.is_binlog_empty()) {
2691 1703 if (thd->lex->sql_command == SQLCOM_CREATE_TABLE &&
2692
2/4
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 27 times.
✗ Branch 3 not taken.
27 !thd->lex->query_block->field_list_is_empty() && /* With select */
2693
6/8
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 811 times.
✓ Branch 2 taken 27 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 27 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 27 times.
✓ Branch 7 taken 811 times.
892 !(thd->lex->create_info->options & HA_LEX_CREATE_TMP_TABLE) &&
2694 27 thd->is_current_stmt_binlog_format_row()) {
2695 /*
2696 In row based binlog format, we reset the binlog statement cache
2697 when rolling back a single statement 'CREATE...SELECT' transaction,
2698 since the 'CREATE TABLE' event was put in the binlog statement cache.
2699 */
2700
1/2
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
27 cache_mngr->stmt_cache.reset();
2701 } else {
2702
2/4
✓ Branch 0 taken 811 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 811 times.
811 if ((error = cache_mngr->stmt_cache.finalize(thd))) goto end;
2703 811 stuff_logged = true;
2704 }
2705 }
2706
2707
3/4
✓ Branch 0 taken 8699 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4587 times.
✓ Branch 3 taken 4112 times.
8700 if (ending_trans(thd, all)) {
2708
3/4
✓ Branch 0 taken 4587 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 482 times.
✓ Branch 3 taken 4105 times.
4587 if (trans_cannot_safely_rollback(thd)) {
2709 482 auto xs = thd->get_transaction()->xid_state();
2710
1/2
✓ Branch 0 taken 482 times.
✗ Branch 1 not taken.
482 std::string query{"ROLLBACK"};
2711
2712
2/4
✓ Branch 0 taken 482 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 482 times.
482 if (is_xa_rollback(thd)) {
2713 /* this block is relevant only for not prepared yet and "local" xa trx
2714 */
2715 assert(
2716 thd->get_transaction()->xid_state()->has_state(XID_STATE::XA_IDLE));
2717
2718 std::ostringstream oss;
2719 oss << "XA ROLLBACK " << *xs->get_xid() << std::flush;
2720 query = oss.str();
2721 }
2722 /*
2723 If the transaction is being rolled back and contains changes that
2724 cannot be rolled back, the trx-cache's content is flushed.
2725 */
2726 482 Query_log_event end_evt(thd, query.data(), query.length(), true, false,
2727
1/2
✓ Branch 0 taken 482 times.
✗ Branch 1 not taken.
964 true, 0, true);
2728 964 error = thd->lex->sql_command != SQLCOM_XA_ROLLBACK
2729
2/4
✓ Branch 0 taken 482 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 482 times.
✗ Branch 3 not taken.
482 ? cache_mngr->trx_cache.finalize(thd, &end_evt)
2730 : cache_mngr->trx_cache.finalize(thd, &end_evt, xs);
2731 482 stuff_logged = true;
2732 482 } else {
2733 /*
2734 If the transaction is being rolled back and its changes can be
2735 rolled back, the trx-cache's content is truncated.
2736 */
2737
1/2
✓ Branch 0 taken 4105 times.
✗ Branch 1 not taken.
4105 error = cache_mngr->trx_cache.truncate(thd, all);
2738
2739
4/6
✓ Branch 0 taken 4105 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 4103 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
4105 DBUG_EXECUTE_IF("ensure_binlog_cache_is_reset", {
2740 /* Assert that binlog cache is reset at rollback time. */
2741 assert(binlog_cache_is_reset);
2742 binlog_cache_is_reset = false;
2743 };);
2744 }
2745 } else {
2746 /*
2747 If a statement is being rolled back, it is necessary to know
2748 exactly why a statement may not be safely rolled back as in
2749 some specific situations the trx-cache can be truncated.
2750
2751 If a temporary table is created or dropped, the trx-cache is not
2752 truncated. Note that if the stmt-cache is used, there is nothing
2753 to truncate in the trx-cache.
2754
2755 If a non-transactional table is updated and the binlog format is
2756 statement, the trx-cache is not truncated. The trx-cache is used
2757 when the direct option is off and a transactional table has been
2758 updated before the current statement in the context of the
2759 current transaction. Note that if the stmt-cache is used there is
2760 nothing to truncate in the trx-cache.
2761
2762 If other binlog formats are used, updates to non-transactional
2763 tables are written to the stmt-cache and trx-cache can be safely
2764 truncated, if necessary.
2765 */
2766
1/2
✓ Branch 0 taken 4113 times.
✗ Branch 1 not taken.
8225 if (thd->get_transaction()->has_dropped_temp_table(Transaction_ctx::STMT) ||
2767
5/6
✓ Branch 0 taken 4112 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 632 times.
✓ Branch 3 taken 3480 times.
✓ Branch 4 taken 294 times.
✓ Branch 5 taken 3818 times.
8856 thd->get_transaction()->has_created_temp_table(Transaction_ctx::STMT) ||
2768 4113 (thd->get_transaction()->has_modified_non_trans_table(
2769 632 Transaction_ctx::STMT) &&
2770
2/2
✓ Branch 0 taken 294 times.
✓ Branch 1 taken 338 times.
632 thd->variables.binlog_format == BINLOG_FORMAT_STMT)) {
2771 /*
2772 If the statement is being rolled back and dropped or created a
2773 temporary table or modified a non-transactional table and the
2774 statement-based replication is in use, the statement's changes
2775 in the trx-cache are preserved.
2776 */
2777
1/2
✓ Branch 0 taken 294 times.
✗ Branch 1 not taken.
294 cache_mngr->trx_cache.set_prev_position(MY_OFF_T_UNDEF);
2778 } else {
2779 /*
2780 Otherwise, the statement's changes in the trx-cache are
2781 truncated.
2782 */
2783
1/2
✓ Branch 0 taken 3819 times.
✗ Branch 1 not taken.
3818 error = cache_mngr->trx_cache.truncate(thd, all);
2784 }
2785 }
2786
2/2
✓ Branch 0 taken 1293 times.
✓ Branch 1 taken 7407 times.
8700 if (stuff_logged) {
2787 1293 Transaction_ctx *trn_ctx = thd->get_transaction();
2788
1/2
✓ Branch 0 taken 1293 times.
✗ Branch 1 not taken.
1293 trn_ctx->store_commit_parent(
2789 m_dependency_tracker.get_max_committed_timestamp());
2790 }
2791
2792
5/8
✓ Branch 0 taken 8699 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8700 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 8699 times.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
8700 DBUG_PRINT("debug", ("error: %d", error));
2793
3/4
✓ Branch 0 taken 8700 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1293 times.
✓ Branch 3 taken 7407 times.
8700 if (error == 0 && stuff_logged) {
2794
2/4
✓ Branch 0 taken 1293 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1293 times.
✗ Branch 3 not taken.
1293 CONDITIONAL_SYNC_POINT_FOR_TIMESTAMP("before_invoke_before_commit_hook");
2795
7/12
✓ Branch 0 taken 1293 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1275 times.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 18 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 18 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 1293 times.
1293 if (RUN_HOOK(
2796 transaction, before_commit,
2797 (thd, all, thd_get_cache_mngr(thd)->get_trx_cache(),
2798 thd_get_cache_mngr(thd)->get_stmt_cache(),
2799 max<my_off_t>(max_binlog_cache_size, max_binlog_stmt_cache_size),
2800 false))) {
2801 // Reset the thread OK status before changing the outcome.
2802 if (thd->get_stmt_da()->is_ok())
2803 thd->get_stmt_da()->reset_diagnostics_area();
2804 my_error(ER_RUN_HOOK_ERROR, MYF(0), "before_commit");
2805 return RESULT_ABORTED;
2806 }
2807 // XA rollback is always accepted.
2808
2/4
✓ Branch 0 taken 1293 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1293 times.
1293 assert(!thd->get_transaction()
2809 ->get_rpl_transaction_ctx()
2810 ->is_transaction_rollback());
2811
2812
1/2
✓ Branch 0 taken 1290 times.
✗ Branch 1 not taken.
1293 error = ordered_commit(thd, all, /* skip_commit */ true);
2813
2814 // Inform hook listeners that a XA ROLLBACK did commit, that
2815 // is, did log a transaction to the binary log.
2816
6/8
✓ Branch 0 taken 1290 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1290 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 142 times.
✓ Branch 5 taken 1148 times.
✓ Branch 6 taken 142 times.
✓ Branch 7 taken 1148 times.
1290 if (!error && is_xa_rollback(thd))
2817
4/6
✓ Branch 0 taken 142 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
✓ Branch 3 taken 125 times.
✓ Branch 4 taken 17 times.
✗ Branch 5 not taken.
142 (void)RUN_HOOK(transaction, after_commit, (thd, all));
2818 }
2819
2820
3/4
✓ Branch 0 taken 8696 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8589 times.
✓ Branch 3 taken 107 times.
8697 if (check_write_error(thd)) {
2821 /*
2822 We reach this point if the effect of a statement did not properly get into
2823 a cache and need to be rolled back.
2824 */
2825
1/2
✓ Branch 0 taken 107 times.
✗ Branch 1 not taken.
107 error |= cache_mngr->trx_cache.truncate(thd, all);
2826 }
2827
2828 8589 end:
2829 // The caches may be empty if an `XA ROLLBACK` was issued just after `XA
2830 // END`. In that case, the BCG will not be invoked and we need to
2831 // rollback in SEs and finalize GTID state.
2832
9/10
✓ Branch 0 taken 2017444 times.
✓ Branch 1 taken 406 times.
✓ Branch 2 taken 2016215 times.
✓ Branch 3 taken 1229 times.
✓ Branch 4 taken 2016224 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 93 times.
✓ Branch 7 taken 2016131 times.
✓ Branch 8 taken 93 times.
✓ Branch 9 taken 2017766 times.
2017850 if (!error && !stuff_logged && is_xa_rollback(thd)) {
2833
1/2
✓ Branch 0 taken 93 times.
✗ Branch 1 not taken.
93 error = trx_coordinator::rollback_in_engines(thd, all);
2834
6/8
✓ Branch 0 taken 93 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 93 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 66 times.
✓ Branch 5 taken 27 times.
✓ Branch 6 taken 66 times.
✓ Branch 7 taken 27 times.
93 if (!error && !thd->is_error()) {
2835 /*
2836 XA-rollback ignores the gtid_state, if the transaciton
2837 is empty.
2838 */
2839
4/6
✓ Branch 0 taken 66 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 60 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 60 times.
✗ Branch 5 not taken.
66 if (is_empty && !thd->slave_thread) gtid_state->update_on_rollback(thd);
2840 /*
2841 XA-rollback commits the new gtid_state, if transaction
2842 is not empty.
2843 */
2844 else {
2845
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 gtid_state->update_on_commit(thd);
2846 /*
2847 Inform hook listeners that a XA ROLLBACK did commit, that
2848 is, did log a transaction to the binary log.
2849 */
2850
2/6
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
6 (void)RUN_HOOK(transaction, after_commit, (thd, all));
2851 }
2852 }
2853 }
2854 /*
2855 When a statement errors out on auto-commit mode it is rollback
2856 implicitly, so the same should happen to its GTID.
2857 */
2858
2/2
✓ Branch 0 taken 2005085 times.
✓ Branch 1 taken 12374 times.
2017859 if (!thd->in_active_multi_stmt_transaction())
2859
1/2
✓ Branch 0 taken 2006134 times.
✗ Branch 1 not taken.
2005085 gtid_state->update_on_rollback(thd);
2860
2861 /*
2862 TODO: some errors are overwritten, which may cause problem,
2863 fix it later.
2864 */
2865
4/8
✓ Branch 0 taken 2018601 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2018593 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 2018588 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
2018508 DBUG_PRINT("return", ("error: %d", error));
2866 2018502 return error;
2867 2018502 }
2868
2869 /**
2870 @note
2871 How do we handle this (unlikely but legal) case:
2872 @verbatim
2873 [transaction] + [update to non-trans table] + [rollback to savepoint] ?
2874 @endverbatim
2875 The problem occurs when a savepoint is before the update to the
2876 non-transactional table. Then when there's a rollback to the savepoint, if we
2877 simply truncate the binlog cache, we lose the part of the binlog cache where
2878 the update is. If we want to not lose it, we need to write the SAVEPOINT
2879 command and the ROLLBACK TO SAVEPOINT command to the binlog cache. The latter
2880 is easy: it's just write at the end of the binlog cache, but the former
2881 should be *inserted* to the place where the user called SAVEPOINT. The
2882 solution is that when the user calls SAVEPOINT, we write it to the binlog
2883 cache (so no need to later insert it). As transactions are never intermixed
2884 in the binary log (i.e. they are serialized), we won't have conflicts with
2885 savepoint names when using mysqlbinlog or in the slave SQL thread.
2886 Then when ROLLBACK TO SAVEPOINT is called, if we updated some
2887 non-transactional table, we don't truncate the binlog cache but instead write
2888 ROLLBACK TO SAVEPOINT to it; otherwise we truncate the binlog cache (which
2889 will chop the SAVEPOINT command from the binlog cache, which is good as in
2890 that case there is no need to have it in the binlog).
2891 */
2892
2893 15125 static int binlog_savepoint_set(handlerton *, THD *thd, void *sv) {
2894
1/2
✓ Branch 0 taken 15125 times.
✗ Branch 1 not taken.
15125 DBUG_TRACE;
2895 15125 int error = 1;
2896
2897 15125 String log_query;
2898
2/4
✓ Branch 0 taken 15125 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 15125 times.
15125 if (log_query.append(STRING_WITH_LEN("SAVEPOINT ")))
2899 return error;
2900 else
2901 15125 append_identifier(thd, &log_query, thd->lex->ident.str,
2902
1/2
✓ Branch 0 taken 15125 times.
✗ Branch 1 not taken.
15125 thd->lex->ident.length);
2903
2904
1/2
✓ Branch 0 taken 15125 times.
✗ Branch 1 not taken.
15125 int errcode = query_error_code(thd, thd->killed == THD::NOT_KILLED);
2905
1/2
✓ Branch 0 taken 15125 times.
✗ Branch 1 not taken.
15125 Query_log_event qinfo(thd, log_query.c_ptr_safe(), log_query.length(), true,
2906
1/2
✓ Branch 0 taken 15125 times.
✗ Branch 1 not taken.
30250 false, true, errcode);
2907 /*
2908 We cannot record the position before writing the statement
2909 because a rollback to a savepoint (.e.g. consider it "S") would
2910 prevent the savepoint statement (i.e. "SAVEPOINT S") from being
2911 written to the binary log despite the fact that the server could
2912 still issue other rollback statements to the same savepoint (i.e.
2913 "S").
2914 Given that the savepoint is valid until the server releases it,
2915 ie, until the transaction commits or it is released explicitly,
2916 we need to log it anyway so that we don't have "ROLLBACK TO S"
2917 or "RELEASE S" without the preceding "SAVEPOINT S" in the binary
2918 log.
2919 */
2920
2/4
✓ Branch 0 taken 15125 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15125 times.
✗ Branch 3 not taken.
15125 if (!(error = mysql_bin_log.write_event(&qinfo)))
2921
1/2
✓ Branch 0 taken 15125 times.
✗ Branch 1 not taken.
15125 binlog_trans_log_savepos(thd, (my_off_t *)sv);
2922
2923 15125 return error;
2924 15125 }
2925
2926 7653 static int binlog_savepoint_rollback(handlerton *, THD *thd, void *sv) {
2927
1/2
✓ Branch 0 taken 7653 times.
✗ Branch 1 not taken.
7653 DBUG_TRACE;
2928
1/2
✓ Branch 0 taken 7653 times.
✗ Branch 1 not taken.
7653 binlog_cache_mngr *const cache_mngr = thd_get_cache_mngr(thd);
2929 7653 my_off_t pos = *(my_off_t *)sv;
2930
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7653 times.
7653 assert(pos != ~(my_off_t)0);
2931
2932 /*
2933 Write ROLLBACK TO SAVEPOINT to the binlog cache if we have updated some
2934 non-transactional table. Otherwise, truncate the binlog cache starting
2935 from the SAVEPOINT command.
2936 */
2937
3/4
✓ Branch 0 taken 7653 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 7638 times.
7653 if (trans_cannot_safely_rollback(thd)) {
2938 15 String log_query;
2939
2/4
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 15 times.
15 if (log_query.append(STRING_WITH_LEN("ROLLBACK TO ")))
2940 return 1;
2941 else {
2942 /*
2943 Before writing identifier to the binlog, make sure to
2944 quote the identifier properly so as to prevent any SQL
2945 injection on the slave.
2946 */
2947 15 append_identifier(thd, &log_query, thd->lex->ident.str,
2948
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 thd->lex->ident.length);
2949 }
2950
2951
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 int errcode = query_error_code(thd, thd->killed == THD::NOT_KILLED);
2952
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 Query_log_event qinfo(thd, log_query.c_ptr_safe(), log_query.length(), true,
2953
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
30 false, true, errcode);
2954
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 return mysql_bin_log.write_event(&qinfo);
2955 15 }
2956 // Otherwise, we truncate the cache
2957
1/2
✓ Branch 0 taken 7638 times.
✗ Branch 1 not taken.
7638 cache_mngr->trx_cache.restore_savepoint(pos);
2958 /*
2959 When a SAVEPOINT is executed inside a stored function/trigger we force the
2960 pending event to be flushed with a STMT_END_F flag and clear the table maps
2961 as well to ensure that following DMLs will have a clean state to start
2962 with. ROLLBACK inside a stored routine has to finalize possibly existing
2963 current row-based pending event with cleaning up table maps. That ensures
2964 that following DMLs will have a clean state to start with.
2965 */
2966
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 7625 times.
7638 if (thd->in_sub_stmt) thd->clear_binlog_table_maps();
2967 7638 return 0;
2968 7653 }
2969
2970 /**
2971 purge logs, master and slave sides both, related error code
2972 converter.
2973 Called from @c purge_error_message(), @c MYSQL_BIN_LOG::reset_logs()
2974
2975 @param res an error code as used by purging routines
2976
2977 @return the user level error code ER_*
2978 */
2979 148 static uint purge_log_get_error_code(int res) {
2980 148 uint errcode = 0;
2981
2982
4/11
✓ Branch 0 taken 131 times.
✓ Branch 1 taken 11 times.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
148 switch (res) {
2983 131 case 0:
2984 131 break;
2985 11 case LOG_INFO_EOF:
2986 11 errcode = ER_UNKNOWN_TARGET_BINLOG;
2987 11 break;
2988 3 case LOG_INFO_IO:
2989 3 errcode = ER_IO_ERR_LOG_INDEX_READ;
2990 3 break;
2991 case LOG_INFO_INVALID:
2992 errcode = ER_BINLOG_PURGE_PROHIBITED;
2993 break;
2994 case LOG_INFO_SEEK:
2995 errcode = ER_FSEEK_FAIL;
2996 break;
2997 case LOG_INFO_MEM:
2998 errcode = ER_OUT_OF_RESOURCES;
2999 break;
3000 3 case LOG_INFO_FATAL:
3001 3 errcode = ER_BINLOG_PURGE_FATAL_ERR;
3002 3 break;
3003 case LOG_INFO_IN_USE:
3004 errcode = ER_LOG_IN_USE;
3005 break;
3006 case LOG_INFO_EMFILE:
3007 errcode = ER_BINLOG_PURGE_EMFILE;
3008 break;
3009 case LOG_INFO_BACKUP_LOCK:
3010 errcode = ER_CANNOT_PURGE_BINLOG_WITH_BACKUP_LOCK;
3011 break;
3012 default:
3013 errcode = ER_LOG_PURGE_UNKNOWN_ERR;
3014 break;
3015 }
3016
3017 148 return errcode;
3018 }
3019
3020 /**
3021 Check whether binlog state allows to safely release MDL locks after
3022 rollback to savepoint.
3023
3024 @param thd The client thread that executes the transaction.
3025
3026 @return true - It is safe to release MDL locks.
3027 false - If it is not.
3028 */
3029 7622 static bool binlog_savepoint_rollback_can_release_mdl(handlerton *, THD *thd) {
3030
1/2
✓ Branch 0 taken 7622 times.
✗ Branch 1 not taken.
7622 DBUG_TRACE;
3031 /**
3032 If we have not updated any non-transactional tables rollback
3033 to savepoint will simply truncate binlog cache starting from
3034 SAVEPOINT command. So it should be safe to release MDL acquired
3035 after SAVEPOINT command in this case.
3036 */
3037
1/2
✓ Branch 0 taken 7622 times.
✗ Branch 1 not taken.
15244 return !trans_cannot_safely_rollback(thd);
3038 7622 }
3039
3040 /**
3041 Adjust log offset in the binary log file for all running slaves
3042 This class implements call back function for do_for_all_thd().
3043 It is called for each thd in thd list to adjust offset.
3044 */
3045 class Adjust_offset : public Do_THD_Impl {
3046 public:
3047 210 Adjust_offset(my_off_t value) : m_purge_offset(value) {}
3048 899 void operator()(THD *thd) override {
3049 LOG_INFO *linfo;
3050 899 mysql_mutex_lock(&thd->LOCK_thd_data);
3051
2/2
✓ Branch 0 taken 83 times.
✓ Branch 1 taken 816 times.
899 if ((linfo = thd->current_linfo)) {
3052 /*
3053 Index file offset can be less that purge offset only if
3054 we just started reading the index file. In that case
3055 we have nothing to adjust.
3056 */
3057
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 81 times.
83 if (linfo->index_file_offset < m_purge_offset)
3058 2 linfo->fatal = (linfo->index_file_offset != 0);
3059 else
3060 81 linfo->index_file_offset -= m_purge_offset;
3061 }
3062 899 mysql_mutex_unlock(&thd->LOCK_thd_data);
3063 899 }
3064
3065 private:
3066 my_off_t m_purge_offset;
3067 };
3068
3069 /*
3070 Adjust the position pointer in the binary log file for all running slaves.
3071
3072 SYNOPSIS
3073 adjust_linfo_offsets()
3074 purge_offset Number of bytes removed from start of log index file
3075
3076 NOTES
3077 - This is called when doing a PURGE when we delete lines from the
3078 index log file.
3079
3080 REQUIREMENTS
3081 - Before calling this function, we have to ensure that no threads are
3082 using any binary log file before purge_offset.
3083
3084 TODO
3085 - Inform the slave threads that they should sync the position
3086 in the binary log file with flush_relay_log_info.
3087 Now they sync is done for next read.
3088 */
3089 210 static void adjust_linfo_offsets(my_off_t purge_offset) {
3090 210 Adjust_offset adjust_offset(purge_offset);
3091
1/2
✓ Branch 0 taken 210 times.
✗ Branch 1 not taken.
210 Global_THD_manager::get_instance()->do_for_all_thd(&adjust_offset);
3092 210 }
3093
3094 /**
3095 This class implements Call back function for do_for_all_thd().
3096 It is called for each thd in thd list to count
3097 threads using bin log file
3098 */
3099
3100 class Log_in_use : public Do_THD_Impl {
3101 public:
3102 15425 Log_in_use(const char *value) : m_log_name(value), m_count(0) {
3103 15425 m_log_name_len = strlen(m_log_name) + 1;
3104 15425 }
3105 166557 void operator()(THD *thd) override {
3106 LOG_INFO *linfo;
3107 166557 mysql_mutex_lock(&thd->LOCK_thd_data);
3108
2/2
✓ Branch 0 taken 263 times.
✓ Branch 1 taken 166294 times.
166557 if ((linfo = thd->current_linfo)) {
3109
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 263 times.
263 if (!strncmp(m_log_name, linfo->log_file_name, m_log_name_len)) {
3110 LogErr(WARNING_LEVEL, ER_BINLOG_FILE_BEING_READ_NOT_PURGED, m_log_name,
3111 thd->thread_id());
3112 m_count++;
3113 }
3114 }
3115 166557 mysql_mutex_unlock(&thd->LOCK_thd_data);
3116 166557 }
3117 15425 int get_count() { return m_count; }
3118
3119 private:
3120 const char *m_log_name;
3121 size_t m_log_name_len;
3122 int m_count;
3123 };
3124
3125 15425 static int log_in_use(const char *log_name) {
3126 15425 Log_in_use log_in_use(log_name);
3127 #ifndef NDEBUG
3128
3/4
✓ Branch 0 taken 15425 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15235 times.
✓ Branch 3 taken 190 times.
15425 if (current_thd)
3129
3/6
✓ Branch 0 taken 15235 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15235 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 15235 times.
✗ Branch 5 not taken.
15235 DEBUG_SYNC(current_thd, "purge_logs_after_lock_index_before_thread_count");
3130 #endif
3131
1/2
✓ Branch 0 taken 15425 times.
✗ Branch 1 not taken.
15425 Global_THD_manager::get_instance()->do_for_all_thd(&log_in_use);
3132 30850 return log_in_use.get_count();
3133 15425 }
3134
3135 139 static bool purge_error_message(THD *thd, int res) {
3136 uint errcode;
3137
3138
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 131 times.
139 if ((errcode = purge_log_get_error_code(res)) != 0) {
3139 8 my_error(errcode, MYF(0));
3140 8 return true;
3141 }
3142 131 my_ok(thd);
3143 131 return false;
3144 }
3145
3146 275 bool is_transaction_empty(THD *thd) {
3147
1/2
✓ Branch 0 taken 275 times.
✗ Branch 1 not taken.
275 DBUG_TRACE;
3148
1/2
✓ Branch 0 taken 275 times.
✗ Branch 1 not taken.
275 int rw_ha_count = check_trx_rw_engines(thd, Transaction_ctx::SESSION);
3149
1/2
✓ Branch 0 taken 275 times.
✗ Branch 1 not taken.
275 rw_ha_count += check_trx_rw_engines(thd, Transaction_ctx::STMT);
3150 275 return rw_ha_count == 0;
3151 275 }
3152
3153 550 int check_trx_rw_engines(THD *thd, Transaction_ctx::enum_trx_scope trx_scope) {
3154
1/2
✓ Branch 0 taken 550 times.
✗ Branch 1 not taken.
550 DBUG_TRACE;
3155
3156 550 int rw_ha_count = 0;
3157
1/2
✓ Branch 0 taken 550 times.
✗ Branch 1 not taken.
550 auto ha_list = thd->get_transaction()->ha_trx_info(trx_scope);
3158
3159
7/12
✓ Branch 0 taken 550 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 550 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 471 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 471 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1021 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 471 times.
✓ Branch 11 taken 550 times.
1021 for (auto const &ha_info : ha_list) {
3160
2/4
✓ Branch 0 taken 471 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 471 times.
✗ Branch 3 not taken.
471 if (ha_info.is_trx_read_write()) ++rw_ha_count;
3161 550 }
3162 550 return rw_ha_count;
3163 550 }
3164
3165 884 bool is_empty_transaction_in_binlog_cache(const THD *thd) {
3166
1/2
✓ Branch 0 taken 884 times.
✗ Branch 1 not taken.
884 DBUG_TRACE;
3167
3168
1/2
✓ Branch 0 taken 884 times.
✗ Branch 1 not taken.
884 binlog_cache_mngr *const cache_mngr = thd_get_cache_mngr(thd);
3169
6/8
✓ Branch 0 taken 884 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 884 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 10 times.
✓ Branch 5 taken 874 times.
✓ Branch 6 taken 10 times.
✓ Branch 7 taken 874 times.
884 if (cache_mngr != nullptr && cache_mngr->has_empty_transaction()) {
3170 10 return true;
3171 }
3172
3173 874 return false;
3174 884 }
3175
3176 /**
3177 This function checks if a transactional table was updated by the
3178 current transaction.
3179
3180 @param thd The client thread that executed the current statement.
3181 @return
3182 @c true if a transactional table was updated, @c false otherwise.
3183 */
3184 32487457 bool trans_has_updated_trans_table(const THD *thd) {
3185 32487457 binlog_cache_mngr *const cache_mngr = thd_get_cache_mngr(thd);
3186
3187
2/2
✓ Branch 0 taken 24891572 times.
✓ Branch 1 taken 7597393 times.
32488965 return (cache_mngr ? !cache_mngr->trx_cache.is_binlog_empty() : 0);
3188 }
3189
3190 /**
3191 This function checks if a transactional table was updated by the
3192 current statement.
3193
3194 @param ha_list Registered storage engine handler list.
3195 @return
3196 @c true if a transactional table was updated, @c false otherwise.
3197 */
3198 6935810 bool stmt_has_updated_trans_table(Ha_trx_info_list const &ha_list) {
3199
7/12
✓ Branch 0 taken 6936166 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6936531 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12225708 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 5696562 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 12632541 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 12225592 times.
✓ Branch 11 taken 406949 times.
12632186 for (auto const &ha_info : ha_list) {
3200
7/8
✓ Branch 0 taken 12225746 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12220481 times.
✓ Branch 3 taken 5265 times.
✓ Branch 4 taken 6529444 times.
✓ Branch 5 taken 5691108 times.
✓ Branch 6 taken 6529441 times.
✓ Branch 7 taken 5696376 times.
12225708 if (ha_info.is_trx_read_write() && ha_info.ht() != binlog_hton)
3201 6529441 return (true);
3202
4/4
✓ Branch 0 taken 407010 times.
✓ Branch 1 taken 6529412 times.
✓ Branch 2 taken 407150 times.
✓ Branch 3 taken 6529384 times.
13465802 }
3203 407150 return (false);
3204 }
3205
3206 /**
3207 This function checks if a transaction, either a multi-statement
3208 or a single statement transaction is about to commit or not.
3209
3210 @param thd The client thread that executed the current statement.
3211 @param all Committing a transaction (i.e. true) or a statement
3212 (i.e. false).
3213 @return
3214 @c true if committing a transaction, otherwise @c false.
3215 */
3216 28636424 bool ending_trans(THD *thd, const bool all) {
3217
4/4
✓ Branch 0 taken 25046546 times.
✓ Branch 1 taken 3589878 times.
✓ Branch 2 taken 10338698 times.
✓ Branch 3 taken 14708157 times.
28636424 return (all || ending_single_stmt_trans(thd, all));
3218 }
3219
3220 /**
3221 This function checks if a single statement transaction is about
3222 to commit or not.
3223
3224 @param thd The client thread that executed the current statement.
3225 @param all Committing a transaction (i.e. true) or a statement
3226 (i.e. false).
3227 @return
3228 @c true if committing a single statement transaction, otherwise
3229 @c false.
3230 */
3231 25046801 bool ending_single_stmt_trans(THD *thd, const bool all) {
3232
4/4
✓ Branch 0 taken 25046763 times.
✓ Branch 1 taken 38 times.
✓ Branch 2 taken 10338525 times.
✓ Branch 3 taken 14708241 times.
25046801 return (!all && !thd->in_multi_stmt_transaction_mode());
3233 }
3234
3235 /**
3236 This function checks if a transaction cannot be rolled back safely.
3237
3238 @param thd The client thread that executed the current statement.
3239 @return
3240 @c true if cannot be safely rolled back, @c false otherwise.
3241 */
3242 19862 bool trans_cannot_safely_rollback(const THD *thd) {
3243 19862 binlog_cache_mngr *const cache_mngr = thd_get_cache_mngr(thd);
3244
3245 19862 return cache_mngr->trx_cache.cannot_rollback();
3246 }
3247
3248 /**
3249 This function checks if current statement cannot be rollded back safely.
3250
3251 @param thd The client thread that executed the current statement.
3252 @return
3253 @c true if cannot be safely rolled back, @c false otherwise.
3254 */
3255 520098 bool stmt_cannot_safely_rollback(const THD *thd) {
3256 520098 return thd->get_transaction()->cannot_safely_rollback(Transaction_ctx::STMT);
3257 }
3258
3259 /**
3260 Execute a PURGE BINARY LOGS TO @<log@> command.
3261
3262 @param thd Pointer to THD object for the client thread executing the
3263 statement.
3264
3265 @param to_log Name of the last log to purge.
3266
3267 @retval false success
3268 @retval true failure
3269 */
3270 138 bool purge_source_logs_to_file(THD *thd, const char *to_log) {
3271 // first run the purge validations
3272
1/2
✓ Branch 0 taken 138 times.
✗ Branch 1 not taken.
138 auto [is_invalid, invalid_error] = check_purge_conditions(mysql_bin_log);
3273
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 137 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
138 if (is_invalid) return purge_error_message(thd, invalid_error);
3274
3275 char search_file_name[FN_REFLEN];
3276 137 constexpr auto auto_purge{false};
3277 137 constexpr auto include_to_log{false};
3278 137 constexpr auto need_index_lock{true};
3279 137 constexpr auto need_update_threads{true};
3280
1/2
✓ Branch 0 taken 137 times.
✗ Branch 1 not taken.
137 mysql_bin_log.make_log_name(search_file_name, to_log);
3281
1/2
✓ Branch 0 taken 119 times.
✗ Branch 1 not taken.
137 auto purge_error = mysql_bin_log.purge_logs(
3282 search_file_name, include_to_log, need_index_lock, need_update_threads,
3283 nullptr, auto_purge);
3284
1/2
✓ Branch 0 taken 119 times.
✗ Branch 1 not taken.
119 return purge_error_message(thd, purge_error);
3285 }
3286
3287 /**
3288 Execute a PURGE BINARY LOGS BEFORE @<date@> command.
3289
3290 @param thd Pointer to THD object for the client thread executing the
3291 statement.
3292
3293 @param purge_time Date before which logs should be purged.
3294
3295 @retval false success
3296 @retval true failure
3297 */
3298 19 bool purge_source_logs_before_date(THD *thd, time_t purge_time) {
3299 // first run the purge validations
3300 19 const auto [is_invalid, invalid_error] =
3301
1/2
✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
19 check_purge_conditions(mysql_bin_log);
3302
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 18 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
19 if (is_invalid) return purge_error_message(thd, invalid_error);
3303
3304 // validations done, now purge
3305 18 constexpr auto auto_purge{false};
3306 auto purge_error =
3307
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 mysql_bin_log.purge_logs_before_date(purge_time, auto_purge);
3308
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 return purge_error_message(thd, purge_error);
3309 }
3310
3311 /**
3312 Check whether the instance is backup locked.
3313
3314 @retval 0 Instance is not backup locked
3315 @retval other Instance is backup locked or failure
3316 */
3317 8835 int check_instance_backup_locked() {
3318 8835 int res{0};
3319
3320 8835 auto is_instance_locked = is_instance_backup_locked(current_thd);
3321
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 31 times.
✓ Branch 2 taken 8804 times.
✗ Branch 3 not taken.
8835 switch (is_instance_locked) {
3322 case Is_instance_backup_locked_result::OOM:
3323 res = LOG_INFO_MEM;
3324 break;
3325 31 case Is_instance_backup_locked_result::LOCKED:
3326 31 res = LOG_INFO_BACKUP_LOCK;
3327 31 break;
3328 8804 case Is_instance_backup_locked_result::NOT_LOCKED:
3329 8804 break;
3330 }
3331
3332 8835 return res;
3333 }
3334
3335 /*
3336 Helper function to get the error code of the query to be binlogged.
3337 */
3338 92634 int query_error_code(const THD *thd, bool not_killed) {
3339 int error;
3340
3341
2/2
✓ Branch 0 taken 92617 times.
✓ Branch 1 taken 17 times.
92634 if (not_killed) {
3342
2/2
✓ Branch 0 taken 885 times.
✓ Branch 1 taken 91732 times.
92617 error = thd->is_error() ? thd->get_stmt_da()->mysql_errno() : 0;
3343
3344 /* thd->get_stmt_da()->sql_errno() might be ER_SERVER_SHUTDOWN or
3345 ER_QUERY_INTERRUPTED, So here we need to make sure that error
3346 is not set to these errors when specified not_killed by the
3347 caller.
3348 */
3349
2/4
✓ Branch 0 taken 92617 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 92617 times.
92617 if (error == ER_SERVER_SHUTDOWN || error == ER_QUERY_INTERRUPTED) error = 0;
3350 } else
3351 17 error = thd->killed;
3352
3353 92634 return error;
3354 }
3355
3356 /**
3357 Copy content of 'from' file from offset to 'to' file.
3358
3359 - We do the copy outside of the IO_CACHE as the cache
3360 buffers would just make things slower and more complicated.
3361 In most cases the copy loop should only do one read.
3362
3363 @param from File to copy.
3364 @param to File to copy to.
3365 @param offset Offset in 'from' file.
3366
3367
3368 @retval
3369 0 ok
3370 @retval
3371 -1 error
3372 */
3373 108997 static bool copy_file(IO_CACHE *from, IO_CACHE *to, my_off_t offset) {
3374 int bytes_read;
3375 uchar io_buf[IO_SIZE * 2];
3376
1/2
✓ Branch 0 taken 108997 times.
✗ Branch 1 not taken.
108997 DBUG_TRACE;
3377
3378
1/2
✓ Branch 0 taken 108997 times.
✗ Branch 1 not taken.
108997 mysql_file_seek(from->file, offset, MY_SEEK_SET, MYF(0));
3379 while (true) {
3380
1/2
✓ Branch 0 taken 186923 times.
✗ Branch 1 not taken.
186923 if ((bytes_read = (int)mysql_file_read(from->file, io_buf, sizeof(io_buf),
3381
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 186923 times.
186923 MYF(MY_WME))) < 0)
3382 goto err;
3383
3/4
✓ Branch 0 taken 186923 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 186917 times.
186923 if (DBUG_EVALUATE_IF("fault_injection_copy_part_file", 1, 0))
3384 6 bytes_read = bytes_read / 2;
3385
2/2
✓ Branch 0 taken 108996 times.
✓ Branch 1 taken 77927 times.
186923 if (!bytes_read) break; // end of file
3386
3/4
✓ Branch 0 taken 77927 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 77926 times.
77927 if (mysql_file_write(to->file, io_buf, bytes_read, MYF(MY_WME | MY_NABP)))
3387 1 goto err;
3388 }
3389
3390 108996 return false;
3391
3392 1 err:
3393 1 return true;
3394 108997 }
3395
3396 /**
3397 Load data's io cache specific hook to be executed
3398 before a chunk of data is being read into the cache's buffer
3399 The function instantiates and writes into the binlog
3400 replication events along LOAD DATA processing.
3401
3402 @param file pointer to io-cache
3403 @retval 0 success
3404 @retval 1 failure
3405 */
3406 155946 int log_loaded_block(IO_CACHE *file) {
3407
1/2
✓ Branch 0 taken 155946 times.
✗ Branch 1 not taken.
155946 DBUG_TRACE;
3408 LOAD_FILE_INFO *lf_info;
3409 uint block_len;
3410 /* buffer contains position where we started last read */
3411 155946 uchar *buffer = (uchar *)my_b_get_buffer_start(file);
3412
1/2
✓ Branch 0 taken 155946 times.
✗ Branch 1 not taken.
155946 uint max_event_size = current_thd->variables.max_allowed_packet;
3413 155946 lf_info = (LOAD_FILE_INFO *)file->arg;
3414
2/2
✓ Branch 0 taken 143520 times.
✓ Branch 1 taken 12426 times.
155946 if (lf_info->thd->is_current_stmt_binlog_format_row()) return 0;
3415
6/6
✓ Branch 0 taken 4160 times.
✓ Branch 1 taken 8266 times.
✓ Branch 2 taken 4114 times.
✓ Branch 3 taken 46 times.
✓ Branch 4 taken 4114 times.
✓ Branch 5 taken 8312 times.
16586 if (lf_info->last_pos_in_file != HA_POS_ERROR &&
3416 4160 lf_info->last_pos_in_file >= my_b_get_pos_in_file(file))
3417 4114 return 0;
3418
3419
2/2
✓ Branch 0 taken 4182 times.
✓ Branch 1 taken 8312 times.
12494 for (block_len = (uint)(my_b_get_bytes_in_buffer(file)); block_len > 0;
3420 4182 buffer += min(block_len, max_event_size),
3421 4182 block_len -= min(block_len, max_event_size)) {
3422 4182 lf_info->last_pos_in_file = my_b_get_pos_in_file(file);
3423
2/2
✓ Branch 0 taken 49 times.
✓ Branch 1 taken 4133 times.
4182 if (lf_info->logged_data_file) {
3424 98 Append_block_log_event a(lf_info->thd, lf_info->thd->db().str, buffer,
3425 49 min(block_len, max_event_size),
3426
1/2
✓ Branch 0 taken 49 times.
✗ Branch 1 not taken.
49 lf_info->log_delayed);
3427
2/4
✓ Branch 0 taken 49 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 49 times.
49 if (mysql_bin_log.write_event(&a)) return 1;
3428
1/2
✓ Branch 0 taken 49 times.
✗ Branch 1 not taken.
49 } else {
3429 8266 Begin_load_query_log_event b(lf_info->thd, lf_info->thd->db().str, buffer,
3430 4133 min(block_len, max_event_size),
3431
1/2
✓ Branch 0 taken 4133 times.
✗ Branch 1 not taken.
4133 lf_info->log_delayed);
3432
2/4
✓ Branch 0 taken 4133 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4133 times.
4133 if (mysql_bin_log.write_event(&b)) return 1;
3433 4133 lf_info->logged_data_file = true;
3434
1/2
✓ Branch 0 taken 4133 times.
✗ Branch 1 not taken.
4133 }
3435 }
3436 8312 return 0;
3437 155946 }
3438
3439 /* Helper function for SHOW BINLOG/RELAYLOG EVENTS */
3440 template <class BINLOG_FILE_READER>
3441 36192 bool show_binlog_events(THD *thd, MYSQL_BIN_LOG *binary_log) {
3442 36192 Protocol *protocol = thd->get_protocol();
3443 36192 List<Item> field_list;
3444 36192 std::string errmsg;
3445 36192 LOG_INFO linfo;
3446
3447
1/2
✓ Branch 0 taken 18096 times.
✗ Branch 1 not taken.
36192 DBUG_TRACE;
3448
3449
3/4
✓ Branch 0 taken 1253 times.
✓ Branch 1 taken 16843 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1253 times.
36192 assert(thd->lex->sql_command == SQLCOM_SHOW_BINLOG_EVENTS ||
3450 thd->lex->sql_command == SQLCOM_SHOW_RELAYLOG_EVENTS);
3451
3452
2/2
✓ Branch 0 taken 18090 times.
✓ Branch 1 taken 6 times.
36192 if (binary_log->is_open()) {
3453 36180 LEX_MASTER_INFO *lex_mi = &thd->lex->mi;
3454 36180 Query_expression *unit = thd->lex->unit;
3455 ha_rows event_count, limit_start, limit_end;
3456 36180 my_off_t pos =
3457 36180 max<my_off_t>(BIN_LOG_HEADER_SIZE, lex_mi->pos); // user-friendly
3458 char search_file_name[FN_REFLEN], *name;
3459 36180 const char *log_file_name = lex_mi->log_file_name;
3460 36180 Log_event *ev = nullptr;
3461
3462
1/2
✓ Branch 0 taken 18090 times.
✗ Branch 1 not taken.
36180 unit->set_limit(thd, thd->lex->current_query_block());
3463 36180 limit_start = unit->offset_limit_cnt;
3464 36180 limit_end = unit->select_limit_cnt;
3465
3466 36180 name = search_file_name;
3467
2/2
✓ Branch 0 taken 14272 times.
✓ Branch 1 taken 3818 times.
36180 if (log_file_name)
3468
1/2
✓ Branch 0 taken 14272 times.
✗ Branch 1 not taken.
28544 binary_log->make_log_name(search_file_name, log_file_name);
3469 else
3470 7636 name = nullptr; // Find first log
3471
3472 36180 linfo.index_file_offset = 0;
3473
3474
3/4
✓ Branch 0 taken 18090 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 18077 times.
36180 if (binary_log->find_log_pos(&linfo, name, true /*need_lock_index=true*/)) {
3475
1/2
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
26 errmsg = "Could not find target log";
3476 60 goto err;
3477 }
3478
3479
1/2
✓ Branch 0 taken 18077 times.
✗ Branch 1 not taken.
36154 mysql_mutex_lock(&thd->LOCK_thd_data);
3480 36154 thd->current_linfo = &linfo;
3481
1/2
✓ Branch 0 taken 18077 times.
✗ Branch 1 not taken.
36154 mysql_mutex_unlock(&thd->LOCK_thd_data);
3482
3483
1/2
✓ Branch 0 taken 18077 times.
✗ Branch 1 not taken.
36154 BINLOG_FILE_READER binlog_file_reader(
3484 opt_source_verify_checksum,
3485 36154 std::max(thd->variables.max_allowed_packet,
3486 36154 binlog_row_event_max_size + MAX_LOG_EVENT_HEADER));
3487
3488
3/4
✓ Branch 0 taken 18077 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
✓ Branch 3 taken 18060 times.
36154 if (binlog_file_reader.open(linfo.log_file_name, pos)) {
3489
2/4
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
34 errmsg = binlog_file_reader.get_error_str();
3490 34 goto err;
3491 }
3492
3493 /*
3494 Adjust the pos to the correct starting offset of an event after the
3495 specified position if it is an invalid starting offset.
3496 */
3497 36120 pos = binlog_file_reader.position();
3498
3499 /*
3500 For 'in-active' binlog file, it is safe to read all events in it. But
3501 for 'active' binlog file, it is only safe to read the events before
3502 get_binlog_end_pos().
3503
3504 Binlog rotation may happen after calling is_active(). In this case,
3505 end_pos will NOT be set to 0 while the file is actually not 'active'.
3506 It is safe, since 'end_pos' still expresses a correct position.
3507 */
3508 36120 my_off_t end_pos = binary_log->get_binlog_end_pos();
3509
3/4
✓ Branch 0 taken 18060 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 244 times.
✓ Branch 3 taken 17816 times.
36120 if (!binary_log->is_active(linfo.log_file_name)) end_pos = 0;
3510
3511
2/4
✓ Branch 0 taken 18060 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18060 times.
✗ Branch 3 not taken.
36120 DEBUG_SYNC(thd, "after_show_binlog_event_found_file");
3512
3513 /**
3514 Relaylog_file_reader and Binlog_file_reader are typedefs to
3515 Basic_binlog_file_reader whereas Relaylog_file_reader uses
3516 a Relaylog_ifile in the template instantiation and
3517 Binlog_file_reader uses a Binlog_ifile in the template
3518 instantiation.
3519
3520 Binlog_ifile and Relaylog_ifile differ only in the open()
3521 member function and they both derive from Basic_binlog_ifile.
3522
3523 Therefore, it is OK to cast to Binlog_file_reader here.
3524
3525 TODO: in the future investigate if some refactoring is needed
3526 here. Perhaps make the Iterator itself templated.
3527 */
3528
1/2
✓ Branch 0 taken 18060 times.
✗ Branch 1 not taken.
36120 binlog::tools::Iterator it(
3529 reinterpret_cast<Binlog_file_reader *>(&binlog_file_reader));
3530
3531 /*
3532 Unpacked events shall copy their part of the buffer from uncompressed
3533 buffer (the cointainer, i.e., the buffer iterator goes out of scope
3534 once the events are inflated and put in a vector). However, it is
3535 unclear if the *buffer* from which events are deserialized is still
3536 needed for the porposes of displaying events in SHOW BINLOG/RELAYLOG
3537 EVENTS.
3538 */
3539 36120 my_off_t last_log_pos = 0;
3540
4/6
✓ Branch 0 taken 18060 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 207113 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 201144 times.
✓ Branch 5 taken 5969 times.
414226 for (event_count = 0, ev = it.begin(); ev != it.end();) {
3541
2/4
✓ Branch 0 taken 201144 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 201144 times.
✗ Branch 3 not taken.
402288 DEBUG_SYNC(thd, "wait_in_show_binlog_events_loop");
3542
3/4
✓ Branch 0 taken 200877 times.
✓ Branch 1 taken 267 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 201144 times.
804042 if (event_count >= limit_start &&
3543
2/4
✓ Branch 0 taken 200877 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 200877 times.
401754 ev->net_send(protocol, linfo.log_file_name, pos)) {
3544 /* purecov: begin inspected */
3545 errmsg = "Net error";
3546 delete ev;
3547 ev = nullptr;
3548 goto err;
3549 /* purecov: end */
3550 }
3551 402288 last_log_pos = ev->common_header->log_pos;
3552
1/2
✓ Branch 0 taken 201144 times.
✗ Branch 1 not taken.
402288 delete ev;
3553 402288 ev = nullptr;
3554 402288 pos = binlog_file_reader.position();
3555
3556
2/2
✓ Branch 0 taken 1543 times.
✓ Branch 1 taken 199601 times.
402288 if (++event_count == limit_end) break;
3557
4/6
✓ Branch 0 taken 199601 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 199601 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 10547 times.
✓ Branch 5 taken 189054 times.
399202 if ((ev = it.next()) == it.end()) break;
3558
2/4
✓ Branch 0 taken 189054 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 189054 times.
378108 if (it.has_error()) break;
3559
4/4
✓ Branch 0 taken 187359 times.
✓ Branch 1 taken 1695 times.
✓ Branch 2 taken 187 times.
✓ Branch 3 taken 187172 times.
378108 if (end_pos > 0 && pos >= end_pos &&
3560
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 186 times.
374 (ev->common_header->log_pos != last_log_pos)) {
3561
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
2 delete ev;
3562 2 ev = nullptr;
3563 2 break;
3564 }
3565 }
3566
3567
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 18059 times.
36120 if (binlog_file_reader.has_fatal_error())
3568
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
2 errmsg = binlog_file_reader.get_error_str();
3569
2/4
✓ Branch 0 taken 18059 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 18059 times.
36118 else if (it.has_error())
3570 errmsg = it.get_error_message(); /* purecov: inspected */
3571 else
3572
1/2
✓ Branch 0 taken 18059 times.
✗ Branch 1 not taken.
36118 errmsg = "";
3573
3/4
✓ Branch 0 taken 18060 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18060 times.
✓ Branch 3 taken 17 times.
36154 }
3574 // Check that linfo is still on the function scope.
3575
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 18066 times.
✓ Branch 2 taken 18066 times.
✗ Branch 3 not taken.
36132 DEBUG_SYNC(thd, "after_show_binlog_events");
3576
3577 err:
3578
2/2
✓ Branch 0 taken 31 times.
✓ Branch 1 taken 18065 times.
36192 if (!errmsg.empty()) {
3579
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 29 times.
62 if (thd->lex->sql_command == SQLCOM_SHOW_RELAYLOG_EVENTS)
3580
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
4 my_error(ER_ERROR_WHEN_EXECUTING_COMMAND, MYF(0), "SHOW RELAYLOG EVENTS",
3581 errmsg.c_str());
3582 else
3583
1/2
✓ Branch 0 taken 29 times.
✗ Branch 1 not taken.
58 my_error(ER_ERROR_WHEN_EXECUTING_COMMAND, MYF(0), "SHOW BINLOG EVENTS",
3584 errmsg.c_str());
3585 } else
3586
1/2
✓ Branch 0 taken 18065 times.
✗ Branch 1 not taken.
36130 my_eof(thd);
3587
3588
1/2
✓ Branch 0 taken 18096 times.
✗ Branch 1 not taken.
36192 mysql_mutex_lock(&thd->LOCK_thd_data);
3589 36192 thd->current_linfo = nullptr;
3590
1/2
✓ Branch 0 taken 18096 times.
✗ Branch 1 not taken.
36192 mysql_mutex_unlock(&thd->LOCK_thd_data);
3591 72384 return !errmsg.empty();
3592 36192 }
3593
3594 18096 bool show_binlog_events(THD *thd, MYSQL_BIN_LOG *binary_log) {
3595
2/2
✓ Branch 0 taken 1253 times.
✓ Branch 1 taken 16843 times.
18096 if (binary_log->is_relay_log)
3596 1253 return show_binlog_events<Relaylog_file_reader>(thd, binary_log);
3597 16843 return show_binlog_events<Binlog_file_reader>(thd, binary_log);
3598 }
3599
3600 /**
3601 Execute a SHOW BINLOG EVENTS statement.
3602
3603 @param thd Pointer to THD object for the client thread executing the
3604 statement.
3605
3606 @retval false success
3607 @retval true failure
3608 */
3609 16843 bool mysql_show_binlog_events(THD *thd) {
3610
1/2
✓ Branch 0 taken 16843 times.
✗ Branch 1 not taken.
16843 DBUG_TRACE;
3611
3612
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16843 times.
16843 assert(thd->lex->sql_command == SQLCOM_SHOW_BINLOG_EVENTS);
3613
3614 16843 mem_root_deque<Item *> field_list(thd->mem_root);
3615
1/2
✓ Branch 0 taken 16843 times.
✗ Branch 1 not taken.
16843 Log_event::init_show_field_list(&field_list);
3616
2/4
✓ Branch 0 taken 16843 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 16843 times.
16843 if (thd->send_result_metadata(field_list,
3617 Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
3618 return true;
3619
3620 /*
3621 Wait for handlers to insert any pending information
3622 into the binlog. For e.g. ndb which updates the binlog asynchronously
3623 this is needed so that the uses sees all its own commands in the binlog
3624 */
3625
1/2
✓ Branch 0 taken 16843 times.
✗ Branch 1 not taken.
16843 ha_binlog_wait(thd);
3626
3627
1/2
✓ Branch 0 taken 16843 times.
✗ Branch 1 not taken.
16843 return show_binlog_events(thd, &mysql_bin_log);
3628 16843 }
3629
3630 137328 MYSQL_BIN_LOG::MYSQL_BIN_LOG(uint *sync_period, bool relay_log)
3631 137328 : name(nullptr),
3632 137328 write_error(false),
3633 137328 inited(false),
3634
1/2
✓ Branch 0 taken 137328 times.
✗ Branch 1 not taken.
137328 m_binlog_file(new Binlog_ofile()),
3635 137328 m_key_LOCK_log(key_LOG_LOCK_log),
3636 137328 bytes_written(0),
3637 137328 binlog_space_total(0),
3638 137328 file_id(1),
3639 137328 sync_period_ptr(sync_period),
3640 137328 sync_counter(0),
3641 137328 is_relay_log(relay_log),
3642 137328 checksum_alg_reset(binary_log::BINLOG_CHECKSUM_ALG_UNDEF),
3643 137328 relay_log_checksum_alg(binary_log::BINLOG_CHECKSUM_ALG_UNDEF),
3644 137328 previous_gtid_set_relaylog(nullptr),
3645 137328 snapshot_lock_acquired(false),
3646
1/2
✓ Branch 0 taken 137328 times.
✗ Branch 1 not taken.
274656 is_rotating_caused_by_incident(false) {
3647 /*
3648 We don't want to initialize locks here as such initialization depends on
3649 safe_mutex (when using safe_mutex) which depends on MY_INIT(), which is
3650 called only in main(). Doing initialization here would make it happen
3651 before main().
3652 */
3653 137328 index_file_name[0] = 0;
3654 137328 }
3655
3656
2/2
✓ Branch 0 taken 101519 times.
✓ Branch 1 taken 31099 times.
265236 MYSQL_BIN_LOG::~MYSQL_BIN_LOG() { delete m_binlog_file; }
3657
3658 /* this is called only once */
3659
3660 31101 void MYSQL_BIN_LOG::cleanup() {
3661
1/2
✓ Branch 0 taken 31101 times.
✗ Branch 1 not taken.
31101 DBUG_TRACE;
3662
2/2
✓ Branch 0 taken 31099 times.
✓ Branch 1 taken 2 times.
31101 if (inited) {
3663 31099 inited = false;
3664
1/2
✓ Branch 0 taken 31099 times.
✗ Branch 1 not taken.
31099 close(LOG_CLOSE_INDEX | LOG_CLOSE_STOP_EVENT, true /*need_lock_log=true*/,
3665 true /*need_lock_index=true*/);
3666
1/2
✓ Branch 0 taken 31099 times.
✗ Branch 1 not taken.
31099 mysql_mutex_destroy(&LOCK_log);
3667
1/2
✓ Branch 0 taken 31099 times.
✗ Branch 1 not taken.
31099 mysql_mutex_destroy(&LOCK_index);
3668
1/2
✓ Branch 0 taken 31099 times.
✗ Branch 1 not taken.
31099 mysql_mutex_destroy(&LOCK_commit);
3669
1/2
✓ Branch 0 taken 31099 times.
✗ Branch 1 not taken.
31099 mysql_mutex_destroy(&LOCK_sync);
3670
1/2
✓ Branch 0 taken 31099 times.
✗ Branch 1 not taken.
31099 mysql_mutex_destroy(&LOCK_binlog_end_pos);
3671
1/2
✓ Branch 0 taken 31099 times.
✗ Branch 1 not taken.
31099 mysql_mutex_destroy(&LOCK_xids);
3672
1/2
✓ Branch 0 taken 31099 times.
✗ Branch 1 not taken.
31099 mysql_cond_destroy(&update_cond);
3673
1/2
✓ Branch 0 taken 31099 times.
✗ Branch 1 not taken.
31099 mysql_cond_destroy(&m_prep_xids_cond);
3674
2/2
✓ Branch 0 taken 10524 times.
✓ Branch 1 taken 20575 times.
31099 if (!is_relay_log) {
3675
2/4
✓ Branch 0 taken 10524 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10524 times.
✗ Branch 3 not taken.
10524 Commit_stage_manager::get_instance().deinit();
3676 }
3677 }
3678
3679
2/2
✓ Branch 0 taken 31099 times.
✓ Branch 1 taken 2 times.
31101 delete m_binlog_file;
3680 31101 m_binlog_file = nullptr;
3681 31101 }
3682
3683 34316 void MYSQL_BIN_LOG::init_pthread_objects() {
3684
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34316 times.
34316 assert(inited == 0);
3685 34316 inited = true;
3686
3687 34316 mysql_mutex_init(m_key_LOCK_log, &LOCK_log, MY_MUTEX_INIT_SLOW);
3688 34316 mysql_mutex_init(m_key_LOCK_index, &LOCK_index, MY_MUTEX_INIT_SLOW);
3689 34316 mysql_mutex_init(m_key_LOCK_commit, &LOCK_commit, MY_MUTEX_INIT_FAST);
3690 34316 mysql_mutex_init(m_key_LOCK_sync, &LOCK_sync, MY_MUTEX_INIT_FAST);
3691 34316 mysql_mutex_init(m_key_LOCK_binlog_end_pos, &LOCK_binlog_end_pos,
3692 MY_MUTEX_INIT_FAST);
3693 34316 mysql_mutex_init(m_key_LOCK_xids, &LOCK_xids, MY_MUTEX_INIT_FAST);
3694 34316 mysql_cond_init(m_key_update_cond, &update_cond);
3695 34316 mysql_cond_init(m_key_prep_xids_cond, &m_prep_xids_cond);
3696
2/2
✓ Branch 0 taken 12142 times.
✓ Branch 1 taken 22174 times.
34316 if (!is_relay_log) {
3697 12142 Commit_stage_manager::get_instance().init(
3698 m_key_LOCK_flush_queue, m_key_LOCK_sync_queue, m_key_LOCK_commit_queue,
3699 m_key_LOCK_done, m_key_COND_done, m_key_COND_flush_queue);
3700 }
3701 34316 }
3702
3703 /**
3704 Check if a string is a valid number.
3705
3706 @param str String to test
3707 @param res Store value here
3708 @param allow_wildcards Set to 1 if we should ignore '%' and '_'
3709
3710 @note
3711 For the moment the allow_wildcards argument is not used
3712 Should be moved to some other file.
3713
3714 @retval
3715 1 String is a number
3716 @retval
3717 0 String is not a number
3718 */
3719
3720 4892428 static bool is_number(const char *str, ulong *res, bool allow_wildcards) {
3721 int flag;
3722 const char *start;
3723
1/2
✓ Branch 0 taken 4892428 times.
✗ Branch 1 not taken.
4892428 DBUG_TRACE;
3724
3725 4892428 flag = 0;
3726 4892428 start = str;
3727
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4892428 times.
4892428 while (*str++ == ' ')
3728 ;
3729
3/6
✓ Branch 0 taken 4892428 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4892428 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 4892428 times.
4892428 if (*--str == '-' || *str == '+') str++;
3730
3/4
✓ Branch 0 taken 28241944 times.
✓ Branch 1 taken 4892428 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4892428 times.
33134372 while (my_isdigit(files_charset_info, *str) ||
3731 (allow_wildcards && (*str == wild_many || *str == wild_one))) {
3732 28241944 flag = 1;
3733 28241944 str++;
3734 }
3735
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 4892418 times.
4892428 if (*str == '.') {
3736
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 10 times.
10 for (str++; my_isdigit(files_charset_info, *str) ||
3737 (allow_wildcards && (*str == wild_many || *str == wild_one));
3738 str++, flag = 1)
3739 ;
3740 }
3741
3/4
✓ Branch 0 taken 4706968 times.
✓ Branch 1 taken 185460 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4706968 times.
4892428 if (*str != 0 || flag == 0) return false;
3742
1/2
✓ Branch 0 taken 4706968 times.
✗ Branch 1 not taken.
4706968 if (res) *res = atol(start);
3743 4706968 return true; /* Number ok */
3744 4892428 } /* is_number */
3745
3746 /**
3747 Find a unique filename for 'filename.#'.
3748
3749 Set '#' to the highest existing log file extension plus one.
3750
3751 This function will return nonzero if: (i) the generated name
3752 exceeds FN_REFLEN; (ii) if the number of extensions is exhausted;
3753 or (iii) some other error happened while examining the filesystem.
3754
3755 @return
3756 nonzero if not possible to get unique filename.
3757 */
3758
3759 134957 static int find_uniq_filename(char *name, uint32 new_index_number) {
3760 uint i;
3761 char buff[FN_REFLEN], ext_buf[FN_REFLEN];
3762 134957 MY_DIR *dir_info = nullptr;
3763 struct fileinfo *file_info;
3764 134957 ulong max_found = 0, next = 0, number = 0;
3765 size_t buf_length, length;
3766 char *start, *end;
3767 134957 int error = 0;
3768
1/2
✓ Branch 0 taken 134957 times.
✗ Branch 1 not taken.
134957 DBUG_TRACE;
3769
3770
1/2
✓ Branch 0 taken 134957 times.
✗ Branch 1 not taken.
134957 length = dirname_part(buff, name, &buf_length);
3771 134957 start = name + length;
3772 134957 end = strend(start);
3773
3774 134957 *end = '.';
3775 134957 length = (size_t)(end - start + 1);
3776
3777
7/10
✓ Branch 0 taken 134957 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 134944 times.
✓ Branch 3 taken 13 times.
✓ Branch 4 taken 134944 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 134944 times.
✓ Branch 8 taken 13 times.
✓ Branch 9 taken 134944 times.
134957 if ((DBUG_EVALUATE_IF(
3778 "error_unique_log_filename", 1,
3779 !(dir_info =
3780 my_dir(buff, MYF(MY_DONT_SORT)))))) { // This shouldn't happen
3781 13 my_stpcpy(end, ".1"); // use name+1
3782 13 return 1;
3783 }
3784 134944 file_info = dir_info->dir_entry;
3785
2/2
✓ Branch 0 taken 7878206 times.
✓ Branch 1 taken 134944 times.
8013150 for (i = dir_info->number_off_files; i--; file_info++) {
3786
4/4
✓ Branch 0 taken 4892428 times.
✓ Branch 1 taken 2985778 times.
✓ Branch 2 taken 4706968 times.
✓ Branch 3 taken 3171238 times.
12770634 if (strncmp(file_info->name, start, length) == 0 &&
3787
3/4
✓ Branch 0 taken 4892428 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4706968 times.
✓ Branch 3 taken 185460 times.
4892428 is_number(file_info->name + length, &number, false)) {
3788 4706968 max_found = std::max(max_found, number);
3789 }
3790 }
3791
1/2
✓ Branch 0 taken 134944 times.
✗ Branch 1 not taken.
134944 my_dirend(dir_info);
3792
3793 /* check if reached the maximum possible extension number */
3794
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 134939 times.
134944 if (max_found >= MAX_LOG_UNIQUE_FN_EXT) {
3795
8/16
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 5 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 5 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 5 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 5 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 5 times.
✗ Branch 15 not taken.
5 LogErr(ERROR_LEVEL, ER_BINLOG_FILE_EXTENSION_NUMBER_EXHAUSTED, max_found);
3796 5 error = 1;
3797 5 goto end;
3798 }
3799
3800
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 134927 times.
134939 if (new_index_number > 0) {
3801 /*
3802 If "new_index_number" was specified, this means we are handling a
3803 "RESET MASTER TO" command and the binary log was already purged
3804 so max_found should be 0.
3805 */
3806
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 assert(max_found == 0);
3807 12 next = new_index_number;
3808 } else
3809 134927 next = max_found + 1;
3810
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 134939 times.
134939 if (sprintf(ext_buf, "%06lu", next) < 0) {
3811 error = 1;
3812 goto end;
3813 }
3814 134939 *end++ = '.';
3815
3816 /*
3817 Check if the generated extension size + the file name exceeds the
3818 buffer size used. If one did not check this, then the filename might be
3819 truncated, resulting in error.
3820 */
3821
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 134939 times.
134939 if (((strlen(ext_buf) + (end - name)) >= FN_REFLEN)) {
3822 LogErr(ERROR_LEVEL, ER_BINLOG_FILE_NAME_TOO_LONG, name, ext_buf,
3823 (strlen(ext_buf) + (end - name)));
3824 error = 1;
3825 goto end;
3826 }
3827
3828
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 134939 times.
134939 if (sprintf(end, "%06lu", next) < 0) {
3829 error = 1;
3830 goto end;
3831 }
3832
3833 /* print warning if reaching the end of available extensions. */
3834
2/2
✓ Branch 0 taken 134931 times.
✓ Branch 1 taken 8 times.
134939 if (next > MAX_ALLOWED_FN_EXT_RESET_MASTER)
3835
8/16
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 8 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 8 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 8 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 8 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 8 times.
✗ Branch 15 not taken.
8 LogErr(WARNING_LEVEL, ER_BINLOG_FILE_EXTENSION_NUMBER_RUNNING_LOW, next,
3836 (MAX_LOG_UNIQUE_FN_EXT - next));
3837
3838 134931 end:
3839 134944 return error;
3840 134957 }
3841
3842 134957 int MYSQL_BIN_LOG::generate_new_name(char *new_name, const char *log_name,
3843 uint32 new_index_number) {
3844 134957 fn_format(new_name, log_name, mysql_data_home, "", 4);
3845
1/2
✓ Branch 0 taken 134957 times.
✗ Branch 1 not taken.
134957 if (!fn_ext(log_name)[0]) {
3846
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 134939 times.
134957 if (find_uniq_filename(new_name, new_index_number)) {
3847
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 2 times.
18 if (current_thd != nullptr)
3848 16 my_printf_error(ER_NO_UNIQUE_LOGFILE,
3849 16 ER_THD(current_thd, ER_NO_UNIQUE_LOGFILE),
3850 MYF(ME_FATALERROR), log_name);
3851
7/14
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 18 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 18 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 18 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 18 times.
✗ Branch 13 not taken.
18 LogErr(ERROR_LEVEL, ER_FAILED_TO_GENERATE_UNIQUE_LOGFILE, log_name);
3852 18 return 1;
3853 }
3854 }
3855 134939 return 0;
3856 }
3857
3858 /**
3859 @todo
3860 The following should be using fn_format(); We just need to
3861 first change fn_format() to cut the file name if it's too long.
3862 */
3863 23605 const char *MYSQL_BIN_LOG::generate_name(const char *log_name,
3864 const char *suffix, char *buff) {
3865
3/4
✓ Branch 0 taken 16305 times.
✓ Branch 1 taken 7300 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 16305 times.
23605 if (!log_name || !log_name[0]) {
3866
3/4
✓ Branch 0 taken 7300 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 49 times.
✓ Branch 3 taken 7251 times.
7300 if (is_relay_log || log_bin_supplied)
3867 49 strmake(buff, default_logfile_name, FN_REFLEN - strlen(suffix) - 1);
3868 else
3869 7251 strmake(buff, default_binlogfile_name, FN_REFLEN - strlen(suffix) - 1);
3870
3871 7300 return (const char *)fn_format(buff, buff, "", suffix,
3872 7300 MYF(MY_REPLACE_EXT | MY_REPLACE_DIR));
3873 }
3874 // get rid of extension to avoid problems
3875
3876 16305 const char *p = fn_ext(log_name);
3877 16305 uint length = (uint)(p - log_name);
3878
1/2
✓ Branch 0 taken 16305 times.
✗ Branch 1 not taken.
16305 strmake(buff, log_name, min<size_t>(length, FN_REFLEN - 1));
3879 16305 return (const char *)buff;
3880 }
3881
3882 168877 bool MYSQL_BIN_LOG::init_and_set_log_file_name(const char *log_name,
3883 const char *new_name,
3884 uint32 new_index_number) {
3885
4/6
✓ Branch 0 taken 67894 times.
✓ Branch 1 taken 100983 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 67894 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 168877 times.
168877 if (new_name && !my_stpcpy(log_file_name, new_name))
3886 return true;
3887
4/4
✓ Branch 0 taken 100983 times.
✓ Branch 1 taken 67894 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 168874 times.
269860 else if (!new_name &&
3888
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 100980 times.
100983 generate_new_name(log_file_name, log_name, new_index_number))
3889 3 return true;
3890
3891 168874 return false;
3892 }
3893
3894 /**
3895 Open the logfile and init IO_CACHE.
3896
3897 @param log_file_key The file instrumentation key for this file
3898 @param log_name The name of the log to open
3899 @param new_name The new name for the logfile.
3900 NULL forces generate_new_name() to be called.
3901 @param new_index_number The binary log file index number to start from
3902 after the RESET MASTER TO command is called.
3903
3904 @return true if error, false otherwise.
3905 */
3906
3907 84432 bool MYSQL_BIN_LOG::open(PSI_file_key log_file_key, const char *log_name,
3908 const char *new_name, uint32 new_index_number) {
3909
1/2
✓ Branch 0 taken 84432 times.
✗ Branch 1 not taken.
84432 DBUG_TRACE;
3910 84432 bool ret = false;
3911
3912 84432 write_error = false;
3913 84432 myf flags = MY_WME | MY_NABP | MY_WAIT_IF_FULL;
3914
2/2
✓ Branch 0 taken 53769 times.
✓ Branch 1 taken 30663 times.
84432 if (is_relay_log) flags = flags | MY_REPORT_WAITING_IF_FULL;
3915
3916
2/4
✓ Branch 0 taken 84432 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 84432 times.
84432 if (!(name = my_strdup(key_memory_MYSQL_LOG_name, log_name, MYF(MY_WME)))) {
3917 goto err;
3918 }
3919
3920
4/6
✓ Branch 0 taken 84432 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 84432 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 84431 times.
168864 if (init_and_set_log_file_name(name, new_name, new_index_number) ||
3921
3/4
✓ Branch 0 taken 84432 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 84431 times.
84432 DBUG_EVALUATE_IF("fault_injection_init_name", 1, 0))
3922 1 goto err;
3923
3924 84431 db[0] = 0;
3925
3926 /* Keep the key for reopen */
3927 84431 m_log_file_key = log_file_key;
3928
3929 /*
3930 LOCK_sync guarantees that no thread is calling m_binlog_file to sync data
3931 to disk when another thread is opening the new file
3932 (FLUSH LOG or RESET MASTER).
3933 */
3934
3/4
✓ Branch 0 taken 30662 times.
✓ Branch 1 taken 53769 times.
✓ Branch 2 taken 30662 times.
✗ Branch 3 not taken.
84431 if (!is_relay_log) mysql_mutex_lock(&LOCK_sync);
3935
3936
1/2
✓ Branch 0 taken 84431 times.
✗ Branch 1 not taken.
84431 ret = m_binlog_file->open(log_file_key, log_file_name, flags);
3937
3938
3/4
✓ Branch 0 taken 30662 times.
✓ Branch 1 taken 53769 times.
✓ Branch 2 taken 30662 times.
✗ Branch 3 not taken.
84431 if (!is_relay_log) mysql_mutex_unlock(&LOCK_sync);
3939
3940
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 84431 times.
84431 if (ret) goto err;
3941
3942 84431 atomic_log_state = LOG_OPENED;
3943 84431 return false;
3944
3945 1 err:
3946
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (binlog_error_action == ABORT_SERVER) {
3947 exec_binlog_error_action_abort(
3948 "Either disk is full, file system is read only or "
3949 "there was an encryption error while opening the binlog. "
3950 "Aborting the server.");
3951 } else
3952
8/16
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 1 times.
✗ Branch 15 not taken.
1 LogErr(ERROR_LEVEL, ER_BINLOG_CANT_OPEN_FOR_LOGGING, log_name, errno);
3953
3954
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 my_free(name);
3955 1 name = nullptr;
3956 1 atomic_log_state = LOG_CLOSED;
3957 1 return true;
3958 84432 }
3959
3960 84651 bool MYSQL_BIN_LOG::open_index_file(const char *index_file_name_arg,
3961 const char *log_name,
3962 bool need_lock_index) {
3963 84651 bool error = false;
3964 84651 File index_file_nr = -1;
3965
2/2
✓ Branch 0 taken 23571 times.
✓ Branch 1 taken 61080 times.
84651 if (need_lock_index)
3966 23571 mysql_mutex_lock(&LOCK_index);
3967 else
3968 61080 mysql_mutex_assert_owner(&LOCK_index);
3969
3970 /*
3971 First open of this class instance
3972 Create an index file that will hold all file names uses for logging.
3973 Add new entries to the end of it.
3974 */
3975 84651 myf opt = MY_UNPACK_FILENAME;
3976
3977
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 84650 times.
84651 if (my_b_inited(&index_file)) goto end;
3978
3979
2/2
✓ Branch 0 taken 23549 times.
✓ Branch 1 taken 61101 times.
84650 if (!index_file_name_arg) {
3980 23549 index_file_name_arg = log_name; // Use same basename for index file
3981 23549 opt = MY_UNPACK_FILENAME | MY_REPLACE_EXT;
3982 }
3983 84650 fn_format(index_file_name, index_file_name_arg, mysql_data_home, ".index",
3984 opt);
3985
3986
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 84650 times.
84650 if (set_crash_safe_index_file_name(index_file_name_arg)) {
3987 error = true;
3988 goto end;
3989 }
3990
3991 /*
3992 We need move crash_safe_index_file to index_file if the index_file
3993 does not exist and crash_safe_index_file exists when mysqld server
3994 restarts.
3995 */
3996
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 37529 times.
122185 if (my_access(index_file_name, F_OK) &&
3997
3/4
✓ Branch 0 taken 37535 times.
✓ Branch 1 taken 47115 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 84650 times.
122185 !my_access(crash_safe_index_file_name, F_OK) &&
3998
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 my_rename(crash_safe_index_file_name, index_file_name, MYF(MY_WME))) {
3999 LogErr(ERROR_LEVEL, ER_BINLOG_CANT_MOVE_TMP_TO_INDEX,
4000 "MYSQL_BIN_LOG::open_index_file");
4001 error = true;
4002 goto end;
4003 }
4004
4005 84650 if ((index_file_nr = mysql_file_open(m_key_file_log_index, index_file_name,
4006 84649 O_RDWR | O_CREAT, MYF(MY_WME))) < 0 ||
4007
1/2
✓ Branch 0 taken 84649 times.
✗ Branch 1 not taken.
84649 mysql_file_sync(index_file_nr, MYF(MY_WME)) ||
4008
1/2
✓ Branch 0 taken 84649 times.
✗ Branch 1 not taken.
84649 init_io_cache_ext(&index_file, index_file_nr, IO_SIZE, READ_CACHE,
4009 mysql_file_seek(index_file_nr, 0L, MY_SEEK_END, MYF(0)),
4010 false, MYF(MY_WME | MY_WAIT_IF_FULL),
4011
4/4
✓ Branch 0 taken 84649 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 84647 times.
169299 m_key_file_log_index_cache) ||
4012
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 84647 times.
84649 DBUG_EVALUATE_IF("fault_injection_openning_index", 1, 0)) {
4013 /*
4014 TODO: all operations creating/deleting the index file or a log, should
4015 call my_sync_dir() or my_sync_dir_by_file() to be durable.
4016 TODO: file creation should be done with mysql_file_create()
4017 not mysql_file_open().
4018 */
4019
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 if (index_file_nr >= 0) mysql_file_close(index_file_nr, MYF(0));
4020 3 error = true;
4021 3 goto end;
4022 }
4023
4024 /*
4025 Sync the index by purging any binary log file that is not registered.
4026 In other words, either purge binary log files that were removed from
4027 the index but not purged from the file system due to a crash or purge
4028 any binary log file that was created but not register in the index
4029 due to a crash.
4030 */
4031
4032 84647 if (set_purge_index_file_name(index_file_name_arg) ||
4033
1/2
✓ Branch 0 taken 84647 times.
✗ Branch 1 not taken.
84647 open_purge_index_file(false) ||
4034
4/8
✓ Branch 0 taken 84647 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 84647 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 84647 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 84647 times.
✗ Branch 7 not taken.
253941 purge_index_entry(nullptr, nullptr, false) || close_purge_index_file() ||
4035
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 84647 times.
84647 DBUG_EVALUATE_IF("fault_injection_recovering_index", 1, 0)) {
4036 LogErr(ERROR_LEVEL, ER_BINLOG_FAILED_TO_SYNC_INDEX_FILE);
4037 error = true;
4038 goto end;
4039 }
4040
4041 84647 end:
4042
2/2
✓ Branch 0 taken 23571 times.
✓ Branch 1 taken 61080 times.
84651 if (need_lock_index) mysql_mutex_unlock(&LOCK_index);
4043 84651 return error;
4044 }
4045
4046 /**
4047 Add the GTIDs from the given relaylog file and also
4048 update the IO thread transaction parser.
4049
4050 @param filename Relaylog file to read from.
4051 @param retrieved_gtids Gtid_set to store the GTIDs found on the relaylog file.
4052 @param verify_checksum Set to true to verify event checksums.
4053 @param trx_parser The transaction boundary parser to be used in order to
4054 only add a GTID to the gtid_set after ensuring the transaction is fully
4055 stored on the relay log.
4056 @param partial_trx The trx_monitoring_info of the last incomplete transaction
4057 found in the relay log.
4058
4059 @retval false The file was successfully read and all GTIDs from
4060 Previous_gtids and Gtid_log_event from complete transactions were added to
4061 the retrieved_set.
4062 @retval true There was an error during the procedure.
4063 */
4064 9732 static bool read_gtids_and_update_trx_parser_from_relaylog(
4065 const char *filename, Gtid_set *retrieved_gtids, bool verify_checksum,
4066 Transaction_boundary_parser *trx_parser,
4067 Gtid_monitoring_info *partial_trx) {
4068
1/2
✓ Branch 0 taken 9732 times.
✗ Branch 1 not taken.
9732 DBUG_TRACE;
4069
3/8
✓ Branch 0 taken 9732 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9732 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 9732 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
9732 DBUG_PRINT("info", ("Opening file %s", filename));
4070
4071
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9732 times.
9732 assert(retrieved_gtids != nullptr);
4072
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9732 times.
9732 assert(trx_parser != nullptr);
4073 #ifndef NDEBUG
4074 9732 unsigned long event_counter = 0;
4075 #endif
4076 9732 bool error = false;
4077
4078
1/2
✓ Branch 0 taken 9732 times.
✗ Branch 1 not taken.
9732 Relaylog_file_reader relaylog_file_reader(verify_checksum);
4079
3/4
✓ Branch 0 taken 9732 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 9726 times.
9732 if (relaylog_file_reader.open(filename)) {
4080
9/18
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 6 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 6 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 6 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 6 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 6 times.
✗ Branch 17 not taken.
6 LogErr(ERROR_LEVEL, ER_BINLOG_FILE_OPEN_FAILED,
4081 relaylog_file_reader.get_error_str());
4082
4083 /*
4084 As read_gtids_from_binlog() will not throw error on truncated
4085 relaylog files, we should do the same here in order to keep the
4086 current behavior.
4087 */
4088
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (relaylog_file_reader.get_error_type() ==
4089 Binlog_read_error::CANNOT_GET_FILE_PASSWORD)
4090 error = true;
4091 6 return error;
4092 }
4093
4094 9726 Log_event *ev = nullptr;
4095 9726 bool seen_prev_gtids = false;
4096 9726 ulong data_len = 0;
4097
4098
6/8
✓ Branch 0 taken 48819 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 48819 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 39093 times.
✓ Branch 5 taken 9726 times.
✓ Branch 6 taken 39093 times.
✓ Branch 7 taken 9726 times.
48819 while (!error && (ev = relaylog_file_reader.read_event_object()) != nullptr) {
4099
3/10
✓ Branch 0 taken 39093 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 39093 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 39093 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
39093 DBUG_PRINT("info", ("Read event of type %s", ev->get_type_str()));
4100 #ifndef NDEBUG
4101 39093 event_counter++;
4102 #endif
4103
4104 39093 data_len = uint4korr(ev->temp_buf + EVENT_LEN_OFFSET);
4105
4106 39093 bool info_error{false};
4107 39093 binary_log::Log_event_basic_info log_event_info;
4108 78186 std::tie(info_error, log_event_info) = extract_log_event_basic_info(
4109
1/2
✓ Branch 0 taken 39093 times.
✗ Branch 1 not taken.
39093 ev->temp_buf, data_len,
4110 39093 relaylog_file_reader.format_description_event());
4111
4112
6/8
✓ Branch 0 taken 39093 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 39093 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 39090 times.
✓ Branch 6 taken 3 times.
✓ Branch 7 taken 39090 times.
39093 if (info_error || trx_parser->feed_event(log_event_info, false)) {
4113 /*
4114 The transaction boundary parser found an error while parsing a
4115 sequence of events from the relaylog. As we don't know if the
4116 parsing has started from a reliable point (it might started in
4117 a relay log file that begins with the rest of a transaction
4118 that started in a previous relay log file), it is better to do
4119 nothing in this case. The boundary parser will fix itself once
4120 finding an event that represent a transaction boundary.
4121
4122 Suppose the following relaylog:
4123
4124 rl-bin.000011 | rl-bin.000012 | rl-bin.000013 | rl-bin-000014
4125 ---------------+---------------+---------------+---------------
4126 PREV_GTIDS | PREV_GTIDS | PREV_GTIDS | PREV_GTIDS
4127 (empty) | (UUID:1-2) | (UUID:1-2) | (UUID:1-2)
4128 ---------------+---------------+---------------+---------------
4129 XID | QUERY(INSERT) | QUERY(INSERT) | XID
4130 ---------------+---------------+---------------+---------------
4131 GTID(UUID:2) |
4132 ---------------+
4133 QUERY(CREATE |
4134 TABLE t1 ...) |
4135 ---------------+
4136 GTID(UUID:3) |
4137 ---------------+
4138 QUERY(BEGIN) |
4139 ---------------+
4140
4141 As it is impossible to determine the current Retrieved_Gtid_Set by only
4142 looking to the PREVIOUS_GTIDS on the last relay log file, and scanning
4143 events on it, we tried to find a relay log file that contains at least
4144 one GTID event during the backwards search.
4145
4146 In the example, we will find a GTID only in rl-bin.000011, as the
4147 UUID:3 transaction was spanned across 4 relay log files.
4148
4149 The transaction spanning can be caused by "FLUSH RELAY LOGS" commands
4150 on slave while it is queuing the transaction.
4151
4152 So, in order to correctly add UUID:3 into Retrieved_Gtid_Set, we need
4153 to parse the relay log starting on the file we found the last GTID
4154 queued to know if the transaction was fully retrieved or not.
4155
4156 Start scanning rl-bin.000011 after resetting the transaction parser
4157 will generate an error, as XID event is only expected inside a DML,
4158 but in this case, we can ignore this error and reset the parser.
4159 */
4160
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 trx_parser->reset();
4161 /*
4162 We also have to discard the GTID of the partial transaction that was
4163 not finished if there is one. This is needed supposing that an
4164 incomplete transaction was replicated with a GTID.
4165
4166 GTID(1), QUERY(BEGIN), QUERY(INSERT), ANONYMOUS_GTID, QUERY(DROP ...)
4167
4168 In the example above, without cleaning the partial_trx,
4169 the GTID(1) would be added to the Retrieved_Gtid_Set after the
4170 QUERY(DROP ...) event.
4171
4172 GTID(1), QUERY(BEGIN), QUERY(INSERT), GTID(2), QUERY(DROP ...)
4173
4174 In the example above the GTID(1) will also be discarded as the
4175 GTID(1) transaction is not complete.
4176 */
4177
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
3 if (partial_trx->is_processing_trx_set()) {
4178 DBUG_PRINT("info",
4179 ("Discarding Gtid(%d, %" PRId64 ") as the transaction "
4180 "wasn't complete and we found an error in the"
4181 "transaction boundary parser.",
4182 partial_trx->get_processing_trx_gtid()->sidno,
4183 partial_trx->get_processing_trx_gtid()->gno));
4184 partial_trx->clear_processing_trx();
4185 }
4186 }
4187
4188
4/4
✓ Branch 0 taken 11939 times.
✓ Branch 1 taken 9726 times.
✓ Branch 2 taken 2892 times.
✓ Branch 3 taken 14536 times.
39093 switch (ev->get_type_code()) {
4189 11939 case binary_log::FORMAT_DESCRIPTION_EVENT:
4190 case binary_log::ROTATE_EVENT:
4191 // do nothing; just accept this event and go to next
4192 11939 break;
4193 9726 case binary_log::PREVIOUS_GTIDS_LOG_EVENT: {
4194 9726 seen_prev_gtids = true;
4195 // add events to sets
4196 9726 Previous_gtids_log_event *prev_gtids_ev =
4197
1/2
✓ Branch 0 taken 9726 times.
✗ Branch 1 not taken.
9726 (Previous_gtids_log_event *)ev;
4198
2/4
✓ Branch 0 taken 9726 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 9726 times.
9726 if (prev_gtids_ev->add_to_set(retrieved_gtids) != 0) {
4199 error = true;
4200 break;
4201 }
4202 #ifndef NDEBUG
4203
1/2
✓ Branch 0 taken 9726 times.
✗ Branch 1 not taken.
9726 char *prev_buffer = prev_gtids_ev->get_str(nullptr, nullptr);
4204
3/8
✓ Branch 0 taken 9726 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9726 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 9726 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
9726 DBUG_PRINT("info", ("Got Previous_gtids from file '%s': Gtid_set='%s'.",
4205 filename, prev_buffer));
4206
1/2
✓ Branch 0 taken 9726 times.
✗ Branch 1 not taken.
9726 my_free(prev_buffer);
4207 #endif
4208 9726 break;
4209 }
4210 2892 case binary_log::GTID_LOG_EVENT: {
4211 /* If we didn't find any PREVIOUS_GTIDS in this file */
4212
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2892 times.
2892 if (!seen_prev_gtids) {
4213 my_error(ER_BINLOG_LOGICAL_CORRUPTION, MYF(0), filename,
4214 "The first global transaction identifier was read, but "
4215 "no other information regarding identifiers existing "
4216 "on the previous log files was found.");
4217 error = true;
4218 break;
4219 }
4220
4221
1/2
✓ Branch 0 taken 2892 times.
✗ Branch 1 not taken.
2892 Gtid_log_event *gtid_ev = (Gtid_log_event *)ev;
4222
1/2
✓ Branch 0 taken 2892 times.
✗ Branch 1 not taken.
2892 rpl_sidno sidno = gtid_ev->get_sidno(retrieved_gtids->get_sid_map());
4223 2892 ulonglong immediate_commit_timestamp =
4224 gtid_ev->immediate_commit_timestamp;
4225 2892 longlong original_commit_timestamp = gtid_ev->original_commit_timestamp;
4226
4227
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2892 times.
2892 if (sidno < 0) {
4228 error = true;
4229 break;
4230 } else {
4231
2/4
✓ Branch 0 taken 2892 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2892 times.
2892 if (retrieved_gtids->ensure_sidno(sidno) != RETURN_STATUS_OK) {
4232 error = true;
4233 break;
4234 } else {
4235 2892 Gtid gtid = {sidno, gtid_ev->get_gno()};
4236 /*
4237 As are updating the transaction boundary parser while reading
4238 GTIDs from relay log files to fill the Retrieved_Gtid_Set, we
4239 should not add the GTID here as we don't know if the transaction
4240 is complete on the relay log yet.
4241 */
4242
1/2
✓ Branch 0 taken 2892 times.
✗ Branch 1 not taken.
2892 partial_trx->start(gtid, original_commit_timestamp,
4243 immediate_commit_timestamp);
4244 }
4245
3/8
✓ Branch 0 taken 2892 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2892 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2892 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
2892 DBUG_PRINT(
4246 "info",
4247 ("Found Gtid in relaylog file '%s': Gtid(%d, %" PRId64 ").",
4248 filename, sidno, gtid_ev->get_gno()));
4249 }
4250 2892 break;
4251 }
4252 14536 case binary_log::ANONYMOUS_GTID_LOG_EVENT:
4253 default:
4254 /*
4255 If we reached the end of a transaction after storing it's GTID
4256 in partial_trx structure, it is time to add this GTID to the
4257 retrieved_gtids set because the transaction is complete and there is
4258 no need for asking this transaction again.
4259 */
4260
2/2
✓ Branch 0 taken 4797 times.
✓ Branch 1 taken 9739 times.
14536 if (trx_parser->is_not_inside_transaction()) {
4261
3/4
✓ Branch 0 taken 4797 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2889 times.
✓ Branch 3 taken 1908 times.
4797 if (partial_trx->is_processing_trx_set()) {
4262 const Gtid *fully_retrieved_gtid;
4263
1/2
✓ Branch 0 taken 2889 times.
✗ Branch 1 not taken.
2889 fully_retrieved_gtid = partial_trx->get_processing_trx_gtid();
4264
3/8
✓ Branch 0 taken 2889 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2889 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2889 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
2889 DBUG_PRINT("info", ("Adding Gtid to Retrieved_Gtid_Set as the "
4265 "transaction was completed at "
4266 "relaylog file '%s': Gtid(%d, %" PRId64 ").",
4267 filename, fully_retrieved_gtid->sidno,
4268 fully_retrieved_gtid->gno));
4269
1/2
✓ Branch 0 taken 2889 times.
✗ Branch 1 not taken.
2889 retrieved_gtids->_add_gtid(*fully_retrieved_gtid);
4270 /*
4271 We don't need to update the last queued structure here. We just
4272 want to have the information about the partial transaction left in
4273 the relay log.
4274 */
4275
1/2
✓ Branch 0 taken 2889 times.
✗ Branch 1 not taken.
2889 partial_trx->clear();
4276 }
4277 }
4278 14536 break;
4279 }
4280
1/2
✓ Branch 0 taken 39093 times.
✗ Branch 1 not taken.
39093 delete ev;
4281 }
4282
4283
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9726 times.
9726 if (relaylog_file_reader.has_fatal_error()) {
4284 // This is not a fatal error; the log may just be truncated.
4285 // @todo but what other errors could happen? IO error?
4286 LogErr(WARNING_LEVEL, ER_BINLOG_ERROR_READING_GTIDS_FROM_RELAY_LOG, -1);
4287 sql_print_warning(relaylog_file_reader.get_error_str());
4288 }
4289
4290 #ifndef NDEBUG
4291
8/16
✓ Branch 0 taken 9726 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9726 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9726 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 9726 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 9726 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 9726 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 9726 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 9726 times.
✗ Branch 15 not taken.
9726 LogErr(INFORMATION_LEVEL, ER_BINLOG_EVENTS_READ_FROM_RELAY_LOG_INFO,
4292 event_counter, filename);
4293 #endif
4294
4295 9726 return error;
4296 9732 }
4297
4298 enum enum_read_gtids_from_binlog_status {
4299 GOT_GTIDS,
4300 GOT_PREVIOUS_GTIDS,
4301 NO_GTIDS,
4302 ERROR,
4303 TRUNCATED
4304 };
4305 /**
4306 Reads GTIDs from the given binlog file.
4307
4308 @param filename File to read from.
4309 @param all_gtids If not NULL, then the GTIDs from the
4310 Previous_gtids_log_event and from all Gtid_log_events are stored in
4311 this object.
4312 @param prev_gtids If not NULL, then the GTIDs from the
4313 Previous_gtids_log_events are stored in this object.
4314 @param first_gtid If not NULL, then the first GTID information from the
4315 file will be stored in this object.
4316 @param sid_map The sid_map object to use in the rpl_sidno generation
4317 of the Gtid_log_event. If lock is needed in the sid_map, the caller
4318 must hold it.
4319 @param verify_checksum Set to true to verify event checksums.
4320 @param is_relay_log Set to true, if filename is a Relay Log, false if it is a
4321 Binary Log.
4322 @retval GOT_GTIDS The file was successfully read and it contains
4323 both Gtid_log_events and Previous_gtids_log_events.
4324 This is only possible if either all_gtids or first_gtid are not null.
4325 @retval GOT_PREVIOUS_GTIDS The file was successfully read and it
4326 contains Previous_gtids_log_events but no Gtid_log_events.
4327 For binary logs, if no all_gtids and no first_gtid are specified,
4328 this function will be done right after reading the PREVIOUS_GTIDS
4329 regardless of the rest of the content of the binary log file.
4330 @retval NO_GTIDS The file was successfully read and it does not
4331 contain GTID events.
4332 @retval ERROR Out of memory, or IO error, or malformed event
4333 structure, or the file is malformed (e.g., contains Gtid_log_events
4334 but no Previous_gtids_log_event).
4335 @retval TRUNCATED The file was truncated before the end of the
4336 first Previous_gtids_log_event.
4337 */
4338 23150 static enum_read_gtids_from_binlog_status read_gtids_from_binlog(
4339 const char *filename, Gtid_set *all_gtids, Gtid_set *prev_gtids,
4340 Gtid *first_gtid, Sid_map *sid_map, bool verify_checksum,
4341 bool is_relay_log) {
4342
1/2
✓ Branch 0 taken 23150 times.
✗ Branch 1 not taken.
23150 DBUG_TRACE;
4343
3/8
✓ Branch 0 taken 23150 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23150 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 23150 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
23150 DBUG_PRINT("info", ("Opening file %s", filename));
4344
4345 #ifndef NDEBUG
4346 23150 unsigned long event_counter = 0;
4347 /*
4348 We assert here that both all_gtids and prev_gtids, if specified,
4349 uses the same sid_map as the one passed as a parameter. This is just
4350 to ensure that, if the sid_map needed some lock and was locked by
4351 the caller, the lock applies to all the GTID sets this function is
4352 dealing with.
4353 */
4354
3/4
✓ Branch 0 taken 15889 times.
✓ Branch 1 taken 7261 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 15889 times.
23150 if (all_gtids) assert(all_gtids->get_sid_map() == sid_map);
4355
3/4
✓ Branch 0 taken 8720 times.
✓ Branch 1 taken 14430 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8720 times.
23150 if (prev_gtids) assert(prev_gtids->get_sid_map() == sid_map);
4356 #endif
4357
4358
1/2
✓ Branch 0 taken 23150 times.
✗ Branch 1 not taken.
23150 Binlog_file_reader binlog_file_reader(verify_checksum);
4359
3/4
✓ Branch 0 taken 23150 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 23143 times.
23150 if (binlog_file_reader.open(filename)) {
4360
9/18
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 7 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 7 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 7 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 7 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 7 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 7 times.
✗ Branch 17 not taken.
7 LogErr(ERROR_LEVEL, ER_BINLOG_FILE_OPEN_FAILED,
4361 binlog_file_reader.get_error_str());
4362 /*
4363 We need to revisit the recovery procedure for relay log
4364 files. Currently, it is called after this routine.
4365 /Alfranio
4366 */
4367
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if (binlog_file_reader.get_error_type() ==
4368 Binlog_read_error::CANNOT_GET_FILE_PASSWORD)
4369 return ERROR;
4370 7 return TRUNCATED;
4371 }
4372
4373 23143 Log_event *ev = nullptr;
4374 23143 enum_read_gtids_from_binlog_status ret = NO_GTIDS;
4375 23143 bool done = false;
4376 23143 bool seen_first_gtid = false;
4377
7/8
✓ Branch 0 taken 34685154 times.
✓ Branch 1 taken 7964 times.
✓ Branch 2 taken 34685154 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 34669975 times.
✓ Branch 5 taken 15179 times.
✓ Branch 6 taken 34669975 times.
✓ Branch 7 taken 23143 times.
34693118 while (!done && (ev = binlog_file_reader.read_event_object()) != nullptr) {
4378 #ifndef NDEBUG
4379 34669975 event_counter++;
4380 #endif
4381
3/10
✓ Branch 0 taken 34669975 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 34669975 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 34669975 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
34669975 DBUG_PRINT("info", ("Read event of type %s", ev->get_type_str()));
4382
5/5
✓ Branch 0 taken 25427 times.
✓ Branch 1 taken 23091 times.
✓ Branch 2 taken 8619 times.
✓ Branch 3 taken 2784459 times.
✓ Branch 4 taken 31828379 times.
34669975 switch (ev->get_type_code()) {
4383 25427 case binary_log::FORMAT_DESCRIPTION_EVENT:
4384 case binary_log::ROTATE_EVENT:
4385 // do nothing; just accept this event and go to next
4386 25427 break;
4387 23091 case binary_log::PREVIOUS_GTIDS_LOG_EVENT: {
4388 23091 ret = GOT_PREVIOUS_GTIDS;
4389 // add events to sets
4390 23091 Previous_gtids_log_event *prev_gtids_ev =
4391
1/2
✓ Branch 0 taken 23091 times.
✗ Branch 1 not taken.
23091 (Previous_gtids_log_event *)ev;
4392
5/8
✓ Branch 0 taken 15848 times.
✓ Branch 1 taken 7243 times.
✓ Branch 2 taken 15848 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 15848 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 23091 times.
23091 if (all_gtids != nullptr && prev_gtids_ev->add_to_set(all_gtids) != 0)
4393 ret = ERROR, done = true;
4394
3/4
✓ Branch 0 taken 8702 times.
✓ Branch 1 taken 14389 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 23091 times.
31793 else if (prev_gtids != nullptr &&
4395
2/4
✓ Branch 0 taken 8702 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 8702 times.
8702 prev_gtids_ev->add_to_set(prev_gtids) != 0)
4396 ret = ERROR, done = true;
4397 #ifndef NDEBUG
4398
1/2
✓ Branch 0 taken 23091 times.
✗ Branch 1 not taken.
23091 char *prev_buffer = prev_gtids_ev->get_str(nullptr, nullptr);
4399
3/8
✓ Branch 0 taken 23091 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23091 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 23091 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
23091 DBUG_PRINT("info", ("Got Previous_gtids from file '%s': Gtid_set='%s'.",
4400 filename, prev_buffer));
4401
1/2
✓ Branch 0 taken 23091 times.
✗ Branch 1 not taken.
23091 my_free(prev_buffer);
4402 #endif
4403 /*
4404 If this is not a relay log, the previous_gtids were asked and no
4405 all_gtids neither first_gtid were asked, it is fine to consider the
4406 job as done.
4407 */
4408
8/8
✓ Branch 0 taken 13367 times.
✓ Branch 1 taken 9724 times.
✓ Branch 2 taken 8702 times.
✓ Branch 3 taken 4665 times.
✓ Branch 4 taken 7243 times.
✓ Branch 5 taken 1459 times.
✓ Branch 6 taken 4732 times.
✓ Branch 7 taken 2511 times.
23091 if (!is_relay_log && prev_gtids != nullptr && all_gtids == nullptr &&
4409 first_gtid == nullptr)
4410 4732 done = true;
4411
2/14
✓ Branch 0 taken 23091 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 23091 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
23091 DBUG_EXECUTE_IF("inject_fault_bug16502579", {
4412 DBUG_PRINT("debug", ("PREVIOUS_GTIDS_LOG_EVENT found. "
4413 "Injected ret=NO_GTIDS."));
4414 if (ret == GOT_PREVIOUS_GTIDS) {
4415 ret = NO_GTIDS;
4416 done = false;
4417 }
4418 });
4419 23091 break;
4420 }
4421 8619 case binary_log::GTID_LOG_EVENT: {
4422
2/2
✓ Branch 0 taken 2438 times.
✓ Branch 1 taken 6181 times.
8619 if (ret != GOT_GTIDS) {
4423
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2438 times.
2438 if (ret != GOT_PREVIOUS_GTIDS) {
4424 /*
4425 Since this routine is run on startup, there may not be a
4426 THD instance. Therefore, ER(X) cannot be used.
4427 */
4428 const char *msg_fmt =
4429 (current_thd != nullptr)
4430 ? ER_THD(current_thd, ER_BINLOG_LOGICAL_CORRUPTION)
4431 : ER_DEFAULT(ER_BINLOG_LOGICAL_CORRUPTION);
4432 my_printf_error(
4433 ER_BINLOG_LOGICAL_CORRUPTION, msg_fmt, MYF(0), filename,
4434 "The first global transaction identifier was read, but "
4435 "no other information regarding identifiers existing "
4436 "on the previous log files was found.");
4437 ret = ERROR, done = true;
4438 break;
4439 } else
4440 2438 ret = GOT_GTIDS;
4441 }
4442 /*
4443 When this is a relaylog, we just check if the relay log contains at
4444 least one Gtid_log_event, so that we can distinguish the return values
4445 GOT_GTID and GOT_PREVIOUS_GTIDS. We don't need to read anything else
4446 from the relay log.
4447 When this is a binary log, if all_gtids is requested (i.e., NOT NULL),
4448 we should continue to read all gtids. If just first_gtid was
4449 requested, we will be done after storing this Gtid_log_event info on
4450 it.
4451 */
4452
2/2
✓ Branch 0 taken 273 times.
✓ Branch 1 taken 8346 times.
8619 if (is_relay_log) {
4453 273 ret = GOT_GTIDS, done = true;
4454 } else {
4455
1/2
✓ Branch 0 taken 8346 times.
✗ Branch 1 not taken.
8346 Gtid_log_event *gtid_ev = (Gtid_log_event *)ev;
4456
1/2
✓ Branch 0 taken 8346 times.
✗ Branch 1 not taken.
8346 rpl_sidno sidno = gtid_ev->get_sidno(sid_map);
4457
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8346 times.
8346 if (sidno < 0)
4458 ret = ERROR, done = true;
4459 else {
4460
2/2
✓ Branch 0 taken 6574 times.
✓ Branch 1 taken 1772 times.
8346 if (all_gtids) {
4461
2/4
✓ Branch 0 taken 6574 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6574 times.
6574 if (all_gtids->ensure_sidno(sidno) != RETURN_STATUS_OK)
4462 ret = ERROR, done = true;
4463
1/2
✓ Branch 0 taken 6574 times.
✗ Branch 1 not taken.
6574 all_gtids->_add_gtid(sidno, gtid_ev->get_gno());
4464
3/8
✓ Branch 0 taken 6574 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6574 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 6574 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
6574 DBUG_PRINT("info",
4465 ("Got Gtid from file '%s': Gtid(%d, %" PRId64 ").",
4466 filename, sidno, gtid_ev->get_gno()));
4467 }
4468
4469 /* If the first GTID was requested, stores it */
4470
3/4
✓ Branch 0 taken 1772 times.
✓ Branch 1 taken 6574 times.
✓ Branch 2 taken 1772 times.
✗ Branch 3 not taken.
8346 if (first_gtid && !seen_first_gtid) {
4471 1772 first_gtid->set(sidno, gtid_ev->get_gno());
4472 1772 seen_first_gtid = true;
4473 /* If the first_gtid was the only thing requested, we are done */
4474
1/2
✓ Branch 0 taken 1772 times.
✗ Branch 1 not taken.
1772 if (all_gtids == nullptr) ret = GOT_GTIDS, done = true;
4475 }
4476 }
4477 }
4478 8619 break;
4479 }
4480 2784459 case binary_log::ANONYMOUS_GTID_LOG_EVENT: {
4481 /*
4482 When this is a relaylog, we just check if it contains
4483 at least one Anonymous_gtid_log_event after initialization
4484 (FDs, Rotates and PREVIOUS_GTIDS), so that we can distinguish the
4485 return values GOT_GTID and GOT_PREVIOUS_GTIDS.
4486 We don't need to read anything else from the relay log.
4487 */
4488
2/2
✓ Branch 0 taken 288 times.
✓ Branch 1 taken 2784171 times.
2784459 if (is_relay_log) {
4489 288 ret = GOT_GTIDS;
4490 288 done = true;
4491 288 break;
4492 }
4493
5/6
✓ Branch 0 taken 1009253 times.
✓ Branch 1 taken 1774918 times.
✓ Branch 2 taken 144 times.
✓ Branch 3 taken 1009109 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 144 times.
2784171 assert(prev_gtids == nullptr
4494 ? true
4495 : all_gtids != nullptr || first_gtid != nullptr);
4496 }
4497 [[fallthrough]];
4498 default:
4499 // if we found any other event type without finding a
4500 // previous_gtids_log_event, then the rest of this binlog
4501 // cannot contain gtids
4502
4/4
✓ Branch 0 taken 34586833 times.
✓ Branch 1 taken 25717 times.
✓ Branch 2 taken 40 times.
✓ Branch 3 taken 34586793 times.
34612550 if (ret != GOT_GTIDS && ret != GOT_PREVIOUS_GTIDS) done = true;
4503 /*
4504 The GTIDs of the relaylog files will be handled later
4505 because of the possibility of transactions be spanned
4506 along distinct relaylog files.
4507 So, if we found an ordinary event without finding the
4508 GTID but we already found the PREVIOUS_GTIDS, this probably
4509 means that the event is from a transaction that started on
4510 previous relaylog file.
4511 */
4512
4/4
✓ Branch 0 taken 34586793 times.
✓ Branch 1 taken 25757 times.
✓ Branch 2 taken 859 times.
✓ Branch 3 taken 34585934 times.
34612550 if (ret == GOT_PREVIOUS_GTIDS && is_relay_log) done = true;
4513 34612550 break;
4514 }
4515
1/2
✓ Branch 0 taken 34669975 times.
✗ Branch 1 not taken.
34669975 delete ev;
4516
3/8
✓ Branch 0 taken 34669975 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 34669975 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 34669975 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
34669975 DBUG_PRINT("info", ("done=%d", done));
4517 }
4518
4519
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 23131 times.
23143 if (binlog_file_reader.has_fatal_error()) {
4520 // This is not a fatal error; the log may just be truncated.
4521
4522 // @todo but what other errors could happen? IO error?
4523
8/16
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 12 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 12 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 12 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 12 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 12 times.
✗ Branch 15 not taken.
12 LogErr(WARNING_LEVEL, ER_BINLOG_ERROR_READING_GTIDS_FROM_BINARY_LOG, -1);
4524
2/4
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
12 sql_print_warning(binlog_file_reader.get_error_str());
4525 }
4526
4527
2/2
✓ Branch 0 taken 15883 times.
✓ Branch 1 taken 7260 times.
23143 if (all_gtids)
4528
1/2
✓ Branch 0 taken 15883 times.
✗ Branch 1 not taken.
15883 all_gtids->dbug_print("all_gtids");
4529 else
4530
3/8
✓ Branch 0 taken 7260 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7260 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 7260 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
7260 DBUG_PRINT("info", ("all_gtids==NULL"));
4531
2/2
✓ Branch 0 taken 8719 times.
✓ Branch 1 taken 14424 times.
23143 if (prev_gtids)
4532
1/2
✓ Branch 0 taken 8719 times.
✗ Branch 1 not taken.
8719 prev_gtids->dbug_print("prev_gtids");
4533 else
4534
3/8
✓ Branch 0 taken 14424 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14424 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 14424 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
14424 DBUG_PRINT("info", ("prev_gtids==NULL"));
4535
2/2
✓ Branch 0 taken 20617 times.
✓ Branch 1 taken 2526 times.
23143 if (first_gtid == nullptr)
4536
3/8
✓ Branch 0 taken 20617 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 20617 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 20617 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
20617 DBUG_PRINT("info", ("first_gtid==NULL"));
4537
2/2
✓ Branch 0 taken 754 times.
✓ Branch 1 taken 1772 times.
2526 else if (first_gtid->sidno == 0)
4538
3/8
✓ Branch 0 taken 754 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 754 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 754 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
754 DBUG_PRINT("info", ("first_gtid.sidno==0"));
4539 else
4540
1/2
✓ Branch 0 taken 1772 times.
✗ Branch 1 not taken.
1772 first_gtid->dbug_print(sid_map, "first_gtid");
4541
4542
3/8
✓ Branch 0 taken 23143 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23143 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 23143 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
23143 DBUG_PRINT("info", ("returning %d", ret));
4543 #ifndef NDEBUG
4544
8/8
✓ Branch 0 taken 13417 times.
✓ Branch 1 taken 9726 times.
✓ Branch 2 taken 8719 times.
✓ Branch 3 taken 4698 times.
✓ Branch 4 taken 7260 times.
✓ Branch 5 taken 1459 times.
✓ Branch 6 taken 4734 times.
✓ Branch 7 taken 2526 times.
23143 if (!is_relay_log && prev_gtids != nullptr && all_gtids == nullptr &&
4545 first_gtid == nullptr)
4546
8/16
✓ Branch 0 taken 4734 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4734 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4734 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 4734 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 4734 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 4734 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 4734 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 4734 times.
✗ Branch 15 not taken.
4734 LogErr(INFORMATION_LEVEL, ER_BINLOG_EVENTS_READ_FROM_BINLOG_INFO,
4547 event_counter, filename);
4548 #endif
4549 23143 return ret;
4550 23150 }
4551
4552 535 bool MYSQL_BIN_LOG::find_first_log(std::string &binlog_file_name,
4553 std::string &errmsg) {
4554
1/2
✓ Branch 0 taken 535 times.
✗ Branch 1 not taken.
535 auto log_index = this->get_log_index();
4555
1/2
✓ Branch 0 taken 535 times.
✗ Branch 1 not taken.
535 std::list<std::string> filename_list = log_index.second;
4556
4557 535 list<string>::iterator fit = filename_list.begin();
4558
1/2
✓ Branch 0 taken 535 times.
✗ Branch 1 not taken.
535 if (fit != filename_list.end()) {
4559
1/2
✓ Branch 0 taken 535 times.
✗ Branch 1 not taken.
535 binlog_file_name.assign(*fit);
4560 } else {
4561 errmsg.assign("Could not find the first log file name in the index file");
4562 return true;
4563 }
4564 535 return false;
4565 535 }
4566
4567 2229 bool MYSQL_BIN_LOG::find_first_log_not_in_gtid_set(char *binlog_file_name,
4568 const Gtid_set *gtid_set,
4569 Gtid *first_gtid,
4570 std::string &errmsg) {
4571
1/2
✓ Branch 0 taken 2229 times.
✗ Branch 1 not taken.
2229 DBUG_TRACE;
4572 2229 LOG_INFO linfo;
4573
1/2
✓ Branch 0 taken 2229 times.
✗ Branch 1 not taken.
2229 auto log_index = this->get_log_index();
4574
1/2
✓ Branch 0 taken 2229 times.
✗ Branch 1 not taken.
2229 std::list<std::string> filename_list = log_index.second;
4575 2229 int error = log_index.first;
4576 2229 list<string>::reverse_iterator rit;
4577
1/2
✓ Branch 0 taken 2229 times.
✗ Branch 1 not taken.
2229 Gtid_set binlog_previous_gtid_set{gtid_set->get_sid_map()};
4578
4579
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2229 times.
2229 if (error != LOG_INFO_EOF) {
4580 errmsg.assign(
4581 "Failed to read the binary log index file while "
4582 "looking for the oldest binary log that contains any GTID "
4583 "that is not in the given gtid set");
4584 error = -1;
4585 goto end;
4586 }
4587
4588
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2229 times.
2229 if (filename_list.empty()) {
4589 errmsg.assign(
4590 "Could not find first log file name in binary log index file "
4591 "while looking for the oldest binary log that contains any GTID "
4592 "that is not in the given gtid set");
4593 error = -2;
4594 goto end;
4595 }
4596
4597 /*
4598 Iterate over all the binary logs in reverse order, and read only
4599 the Previous_gtids_log_event, to find the first one, that is the
4600 subset of the given gtid set. Since every binary log begins with
4601 a Previous_gtids_log_event, that contains all GTIDs in all
4602 previous binary logs.
4603 We also ask for the first GTID in the binary log to know if we
4604 should send the FD event with the "created" field cleared or not.
4605 */
4606
3/8
✓ Branch 0 taken 2229 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2229 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2229 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
2229 DBUG_PRINT("info", ("Iterating backwards through binary logs, and reading "
4607 "only the Previous_gtids_log_event, to find the first "
4608 "one, that is the subset of the given gtid set."));
4609 2229 rit = filename_list.rbegin();
4610 2229 error = 0;
4611
3/4
✓ Branch 0 taken 2253 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2252 times.
✓ Branch 3 taken 1 times.
2253 while (rit != filename_list.rend()) {
4612
1/2
✓ Branch 0 taken 2252 times.
✗ Branch 1 not taken.
2252 binlog_previous_gtid_set.clear();
4613
1/2
✓ Branch 0 taken 2252 times.
✗ Branch 1 not taken.
2252 const char *filename = rit->c_str();
4614
3/8
✓ Branch 0 taken 2252 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2252 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2252 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
2252 DBUG_PRINT("info",
4615 ("Read Previous_gtids_log_event from filename='%s'", filename));
4616
3/7
✓ Branch 0 taken 2252 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 2251 times.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
2252 switch (read_gtids_from_binlog(filename, nullptr, &binlog_previous_gtid_set,
4617 first_gtid,
4618 binlog_previous_gtid_set.get_sid_map(),
4619 2252 opt_source_verify_checksum, is_relay_log)) {
4620 case ERROR:
4621 errmsg.assign(
4622 "Error reading header of binary log while looking for "
4623 "the oldest binary log that contains any GTID that is not in "
4624 "the given gtid set");
4625 error = -3;
4626 goto end;
4627 case NO_GTIDS:
4628 errmsg.assign(
4629 "Found old binary log without GTIDs while looking for "
4630 "the oldest binary log that contains any GTID that is not in "
4631 "the given gtid set");
4632 error = -4;
4633 goto end;
4634 2251 case GOT_GTIDS:
4635 case GOT_PREVIOUS_GTIDS:
4636
3/4
✓ Branch 0 taken 2251 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2228 times.
✓ Branch 3 taken 23 times.
2251 if (binlog_previous_gtid_set.is_subset(gtid_set)) {
4637 2228 strcpy(binlog_file_name, filename);
4638 /*
4639 Verify that the selected binlog is not the first binlog,
4640 */
4641
2/6
✓ Branch 0 taken 2228 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2228 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
2228 DBUG_EXECUTE_IF("replica_reconnect_with_gtid_set_executed",
4642 assert(strcmp(filename_list.begin()->c_str(),
4643 binlog_file_name) != 0););
4644 2228 goto end;
4645 }
4646 case TRUNCATED:
4647 24 break;
4648 }
4649
4650
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 rit++;
4651 }
4652
4653
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1 if (rit == filename_list.rend()) {
4654
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 report_missing_gtids(&binlog_previous_gtid_set, gtid_set, errmsg);
4655 1 error = -5;
4656 }
4657
4658 end:
4659
5/10
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2228 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
2229 if (error) DBUG_PRINT("error", ("'%s'", errmsg.c_str()));
4660 2229 filename_list.clear();
4661
3/8
✓ Branch 0 taken 2229 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2229 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2229 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
2229 DBUG_PRINT("info", ("returning %d", error));
4662 2229 return error != 0 ? true : false;
4663 2229 }
4664
4665 12707 bool MYSQL_BIN_LOG::init_gtid_sets(Gtid_set *all_gtids, Gtid_set *lost_gtids,
4666 bool verify_checksum, bool need_lock,
4667 Transaction_boundary_parser *trx_parser,
4668 Gtid_monitoring_info *partial_trx,
4669 bool is_server_starting) {
4670
1/2
✓ Branch 0 taken 12707 times.
✗ Branch 1 not taken.
12707 DBUG_TRACE;
4671
3/10
✓ Branch 0 taken 12707 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12707 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 12707 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
12707 DBUG_PRINT(
4672 "info",
4673 ("lost_gtids=%p; so we are recovering a %s log; is_relay_log=%d",
4674 lost_gtids, lost_gtids == nullptr ? "relay" : "binary", is_relay_log));
4675
4676 Checkable_rwlock *sid_lock =
4677
2/2
✓ Branch 0 taken 1276 times.
✓ Branch 1 taken 11431 times.
12707 is_relay_log ? all_gtids->get_sid_map()->get_sid_lock() : global_sid_lock;
4678 /*
4679 If this is a relay log, we must have the IO thread Master_info trx_parser
4680 in order to correctly feed it with relay log events.
4681 */
4682 #ifndef NDEBUG
4683
2/2
✓ Branch 0 taken 1276 times.
✓ Branch 1 taken 11431 times.
12707 if (is_relay_log) {
4684
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1276 times.
1276 assert(trx_parser != nullptr);
4685
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1276 times.
1276 assert(lost_gtids == nullptr);
4686 }
4687 #endif
4688
4689 /*
4690 Acquires the necessary locks to ensure that logs are not either
4691 removed or updated when we are reading from it.
4692 */
4693
2/2
✓ Branch 0 taken 12497 times.
✓ Branch 1 taken 210 times.
12707 if (need_lock) {
4694 // We don't need LOCK_log if we are only going to read the initial
4695 // Prevoius_gtids_log_event and ignore the Gtid_log_events.
4696
2/4
✓ Branch 0 taken 12497 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12497 times.
✗ Branch 3 not taken.
12497 if (all_gtids != nullptr) mysql_mutex_lock(&LOCK_log);
4697
1/2
✓ Branch 0 taken 12497 times.
✗ Branch 1 not taken.
12497 mysql_mutex_lock(&LOCK_index);
4698
1/2
✓ Branch 0 taken 12497 times.
✗ Branch 1 not taken.
12497 sid_lock->wrlock();
4699 } else {
4700
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 210 times.
210 if (all_gtids != nullptr) mysql_mutex_assert_owner(&LOCK_log);
4701 210 mysql_mutex_assert_owner(&LOCK_index);
4702
1/2
✓ Branch 0 taken 210 times.
✗ Branch 1 not taken.
210 sid_lock->assert_some_wrlock();
4703 }
4704
4705 /* Initialize the sid_map to be used in read_gtids_from_binlog */
4706 12707 Sid_map *sid_map = nullptr;
4707
2/2
✓ Branch 0 taken 12497 times.
✓ Branch 1 taken 210 times.
12707 if (all_gtids)
4708 12497 sid_map = all_gtids->get_sid_map();
4709
1/2
✓ Branch 0 taken 210 times.
✗ Branch 1 not taken.
210 else if (lost_gtids)
4710 210 sid_map = lost_gtids->get_sid_map();
4711
4712 // Gather the set of files to be accessed.
4713
1/2
✓ Branch 0 taken 12707 times.
✗ Branch 1 not taken.
12707 auto log_index = this->get_log_index(false);
4714
1/2
✓ Branch 0 taken 12707 times.
✗ Branch 1 not taken.
12707 std::list<std::string> filename_list = log_index.second;
4715 12707 int error = log_index.first;
4716 12707 list<string>::iterator it;
4717 12707 list<string>::reverse_iterator rit;
4718 12707 bool reached_first_file = false;
4719
4720
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12707 times.
12707 if (error != LOG_INFO_EOF) {
4721 DBUG_PRINT("error", ("Error reading %s index",
4722 is_relay_log ? "relaylog" : "binlog"));
4723 goto end;
4724 }
4725 /*
4726 On server starting, one new empty binlog file is created and
4727 its file name is put into index file before initializing
4728 GLOBAL.GTID_EXECUTED AND GLOBAL.GTID_PURGED, it is not the
4729 last binlog file before the server restarts, so we remove
4730 its file name from filename_list.
4731 */
4732
6/8
✓ Branch 0 taken 11221 times.
✓ Branch 1 taken 1486 times.
✓ Branch 2 taken 11221 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 11221 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 11221 times.
✓ Branch 7 taken 1486 times.
12707 if (is_server_starting && !is_relay_log && !filename_list.empty())
4733 11221 filename_list.pop_back();
4734
4735 12707 error = 0;
4736
2/2
✓ Branch 0 taken 12497 times.
✓ Branch 1 taken 210 times.
12707 if (all_gtids != nullptr) {
4737
3/12
✓ Branch 0 taken 12497 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12497 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 12497 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
12497 DBUG_PRINT("info", ("Iterating backwards through %s logs, "
4738 "looking for the last %s log that contains "
4739 "a Previous_gtids_log_event.",
4740 is_relay_log ? "relay" : "binary",
4741 is_relay_log ? "relay" : "binary"));
4742 // Iterate over all files in reverse order until we find one that
4743 // contains a Previous_gtids_log_event.
4744 12497 rit = filename_list.rbegin();
4745 12497 bool can_stop_reading = false;
4746
1/2
✓ Branch 0 taken 12497 times.
✗ Branch 1 not taken.
12497 reached_first_file = (rit == filename_list.rend());
4747
3/12
✓ Branch 0 taken 12497 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12497 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 12497 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
12497 DBUG_PRINT("info",
4748 ("filename='%s' reached_first_file=%d",
4749 reached_first_file ? "" : rit->c_str(), reached_first_file));
4750
4/4
✓ Branch 0 taken 21698 times.
✓ Branch 1 taken 6685 times.
✓ Branch 2 taken 15889 times.
✓ Branch 3 taken 5809 times.
28383 while (!can_stop_reading && !reached_first_file) {
4751
1/2
✓ Branch 0 taken 15889 times.
✗ Branch 1 not taken.
15889 const char *filename = rit->c_str();
4752
2/4
✓ Branch 0 taken 15889 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 15889 times.
15889 assert(rit != filename_list.rend());
4753
1/2
✓ Branch 0 taken 15889 times.
✗ Branch 1 not taken.
15889 rit++;
4754
1/2
✓ Branch 0 taken 15889 times.
✗ Branch 1 not taken.
15889 reached_first_file = (rit == filename_list.rend());
4755
3/8
✓ Branch 0 taken 15889 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15889 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 15889 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
15889 DBUG_PRINT("info", ("filename='%s' can_stop_reading=%d "
4756 "reached_first_file=%d, ",
4757 filename, can_stop_reading, reached_first_file));
4758
5/8
✓ Branch 0 taken 15889 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 954 times.
✓ Branch 4 taken 14894 times.
✓ Branch 5 taken 35 times.
✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
15889 switch (read_gtids_from_binlog(
4759 filename, all_gtids, reached_first_file ? lost_gtids : nullptr,
4760
2/2
✓ Branch 0 taken 2171 times.
✓ Branch 1 taken 13718 times.
15889 nullptr /* first_gtid */, sid_map, verify_checksum, is_relay_log)) {
4761 case ERROR: {
4762 error = 1;
4763 goto end;
4764 }
4765 954 case GOT_GTIDS: {
4766 954 can_stop_reading = true;
4767 954 break;
4768 }
4769 14894 case GOT_PREVIOUS_GTIDS: {
4770 /*
4771 If this is a binlog file, it is enough to have GOT_PREVIOUS_GTIDS.
4772 If this is a relaylog file, we need to find at least one GTID to
4773 start parsing the relay log to add GTID of transactions that might
4774 have spanned in distinct relaylog files.
4775 */
4776
2/2
✓ Branch 0 taken 5731 times.
✓ Branch 1 taken 9163 times.
14894 if (!is_relay_log) can_stop_reading = true;
4777 14894 break;
4778 }
4779 35 case NO_GTIDS: {
4780 /*
4781 Mysql server iterates backwards through binary logs, looking for
4782 the last binary log that contains a Previous_gtids_log_event for
4783 gathering the set of gtid_executed on server start. This may take
4784 very long time if it has many binary logs and almost all of them
4785 are out of filesystem cache. So if the binlog_gtid_simple_recovery
4786 is enabled, and the last binary log does not contain any GTID
4787 event, do not read any more binary logs, GLOBAL.GTID_EXECUTED and
4788 GLOBAL.GTID_PURGED should be empty in the case.
4789 */
4790
4/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 30 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 2 times.
35 if (binlog_gtid_simple_recovery && is_server_starting &&
4791
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 !is_relay_log) {
4792
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
3 assert(all_gtids->is_empty());
4793
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
3 assert(lost_gtids->is_empty());
4794 3 goto end;
4795 }
4796 [[fallthrough]];
4797 }
4798 case TRUNCATED: {
4799 38 break;
4800 }
4801 }
4802 }
4803
4804 /*
4805 If we use GTIDs and have partial transactions on the relay log,
4806 must check if it ends on next relay log files.
4807 We also need to feed the boundary parser with the rest of the
4808 relay log to put it in the correct state before receiving new
4809 events from the master in the case of GTID auto positioning be
4810 disabled.
4811 */
4812
6/6
✓ Branch 0 taken 1276 times.
✓ Branch 1 taken 11218 times.
✓ Branch 2 taken 1255 times.
✓ Branch 3 taken 21 times.
✓ Branch 4 taken 1255 times.
✓ Branch 5 taken 11239 times.
12494 if (is_relay_log && filename_list.size() > 0) {
4813 /*
4814 Suppose the following relaylog:
4815
4816 rl-bin.000001 | rl-bin.000002 | rl-bin.000003 | rl-bin-000004
4817 ---------------+---------------+---------------+---------------
4818 PREV_GTIDS | PREV_GTIDS | PREV_GTIDS | PREV_GTIDS
4819 (empty) | (UUID:1) | (UUID:1) | (UUID:1)
4820 ---------------+---------------+---------------+---------------
4821 GTID(UUID:1) | QUERY(INSERT) | QUERY(INSERT) | XID
4822 ---------------+---------------+---------------+---------------
4823 QUERY(CREATE |
4824 TABLE t1 ...) |
4825 ---------------+
4826 GTID(UUID:2) |
4827 ---------------+
4828 QUERY(BEGIN) |
4829 ---------------+
4830
4831 As it is impossible to determine the current Retrieved_Gtid_Set by only
4832 looking to the PREVIOUS_GTIDS on the last relay log file, and scanning
4833 events on it, we tried to find a relay log file that contains at least
4834 one GTID event during the backwards search.
4835
4836 In the example, we will find a GTID only in rl-bin.000001, as the
4837 UUID:2 transaction was spanned across 4 relay log files.
4838
4839 The transaction spanning can be caused by "FLUSH RELAY LOGS" commands
4840 on slave while it is queuing the transaction.
4841
4842 So, in order to correctly add UUID:2 into Retrieved_Gtid_Set, we need
4843 to parse the relay log starting on the file we found the last GTID
4844 queued to know if the transaction was fully retrieved or not.
4845 */
4846
4847 /*
4848 Adjust the reverse iterator to point to the relaylog file we
4849 need to start parsing, as it was incremented after generating
4850 the relay log file name.
4851 */
4852
2/4
✓ Branch 0 taken 1255 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1255 times.
1255 assert(rit != filename_list.rbegin());
4853
1/2
✓ Branch 0 taken 1255 times.
✗ Branch 1 not taken.
1255 rit--;
4854
2/4
✓ Branch 0 taken 1255 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1255 times.
1255 assert(rit != filename_list.rend());
4855 /* Reset the transaction parser before feeding it with events */
4856
1/2
✓ Branch 0 taken 1255 times.
✗ Branch 1 not taken.
1255 trx_parser->reset();
4857
1/2
✓ Branch 0 taken 1255 times.
✗ Branch 1 not taken.
1255 partial_trx->clear();
4858
4859
3/8
✓ Branch 0 taken 1255 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1255 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1255 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
1255 DBUG_PRINT("info", ("Iterating forwards through relay logs, "
4860 "updating the Retrieved_Gtid_Set and updating "
4861 "IO thread trx parser before start."));
4862
1/2
✓ Branch 0 taken 1255 times.
✗ Branch 1 not taken.
1255 for (it = find(filename_list.begin(), filename_list.end(), *rit);
4863
2/2
✓ Branch 0 taken 9732 times.
✓ Branch 1 taken 1255 times.
10987 it != filename_list.end(); it++) {
4864 9732 const char *filename = it->c_str();
4865
3/8
✓ Branch 0 taken 9732 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9732 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 9732 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
9732 DBUG_PRINT("info", ("filename='%s'", filename));
4866
2/4
✓ Branch 0 taken 9732 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 9732 times.
9732 if (read_gtids_and_update_trx_parser_from_relaylog(
4867 filename, all_gtids, true, trx_parser, partial_trx)) {
4868 error = 1;
4869 goto end;
4870 }
4871 }
4872 }
4873 }
4874
4/4
✓ Branch 0 taken 1276 times.
✓ Branch 1 taken 11428 times.
✓ Branch 2 taken 6553 times.
✓ Branch 3 taken 4875 times.
12704 if (lost_gtids != nullptr && !reached_first_file) {
4875 /*
4876 This branch is only reachable by a binary log. The relay log
4877 don't need to get lost_gtids information.
4878
4879 A 5.6 server sets GTID_PURGED by rotating the binary log.
4880
4881 A 5.6 server that had recently enabled GTIDs and set GTID_PURGED
4882 would have a sequence of binary logs like:
4883
4884 master-bin.N : No PREVIOUS_GTIDS (GTID wasn't enabled)
4885 master-bin.N+1: Has an empty PREVIOUS_GTIDS and a ROTATE
4886 (GTID was enabled on startup)
4887 master-bin.N+2: Has a PREVIOUS_GTIDS with the content set by a
4888 SET @@GLOBAL.GTID_PURGED + has GTIDs of some
4889 transactions.
4890
4891 If this 5.6 server be upgraded to 5.7 keeping its binary log files,
4892 this routine will have to find the first binary log that contains a
4893 PREVIOUS_GTIDS + a GTID event to ensure that the content of the
4894 GTID_PURGED will be correctly set (assuming binlog_gtid_simple_recovery
4895 is not enabled).
4896 */
4897
3/8
✓ Branch 0 taken 4875 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4875 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 4875 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
4875 DBUG_PRINT("info", ("Iterating forwards through binary logs, looking for "
4898 "the first binary log that contains both a "
4899 "Previous_gtids_log_event and a Gtid_log_event."));
4900
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4875 times.
4875 assert(!is_relay_log);
4901
2/2
✓ Branch 0 taken 5009 times.
✓ Branch 1 taken 15 times.
5024 for (it = filename_list.begin(); it != filename_list.end(); it++) {
4902 /*
4903 We should pass a first_gtid to read_gtids_from_binlog when
4904 binlog_gtid_simple_recovery is disabled, or else it will return
4905 right after reading the PREVIOUS_GTIDS event to avoid stall on
4906 reading the whole binary log.
4907 */
4908 5009 Gtid first_gtid = {0, 0};
4909 5009 const char *filename = it->c_str();
4910
3/8
✓ Branch 0 taken 5009 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5009 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 5009 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
5009 DBUG_PRINT("info", ("filename='%s'", filename));
4911
3/7
✓ Branch 0 taken 5009 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 126 times.
✓ Branch 4 taken 4883 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
5009 switch (read_gtids_from_binlog(
4912 filename, nullptr, lost_gtids,
4913 binlog_gtid_simple_recovery ? nullptr : &first_gtid, sid_map,
4914
2/2
✓ Branch 0 taken 4734 times.
✓ Branch 1 taken 275 times.
5009 verify_checksum, is_relay_log)) {
4915 case ERROR: {
4916 error = 1;
4917 [[fallthrough]];
4918 }
4919 126 case GOT_GTIDS: {
4920 4860 goto end;
4921 }
4922 4883 case NO_GTIDS:
4923 case GOT_PREVIOUS_GTIDS: {
4924 /*
4925 Mysql server iterates forwards through binary logs, looking for
4926 the first binary log that contains both Previous_gtids_log_event
4927 and gtid_log_event for gathering the set of gtid_purged on server
4928 start. It also iterates forwards through binary logs, looking for
4929 the first binary log that contains both Previous_gtids_log_event
4930 and gtid_log_event for gathering the set of gtid_purged when
4931 purging binary logs. This may take very long time if it has many
4932 binary logs and almost all of them are out of filesystem cache.
4933 So if the binlog_gtid_simple_recovery is enabled, we just
4934 initialize GLOBAL.GTID_PURGED from the first binary log, do not
4935 read any more binary logs.
4936 */
4937
2/2
✓ Branch 0 taken 4734 times.
✓ Branch 1 taken 149 times.
4883 if (binlog_gtid_simple_recovery) goto end;
4938 [[fallthrough]];
4939 }
4940 case TRUNCATED: {
4941 149 break;
4942 }
4943 }
4944 }
4945 }
4946 7829 end:
4947
3/4
✓ Branch 0 taken 12497 times.
✓ Branch 1 taken 210 times.
✓ Branch 2 taken 12497 times.
✗ Branch 3 not taken.
12707 if (all_gtids) all_gtids->dbug_print("all_gtids");
4948
3/4
✓ Branch 0 taken 11431 times.
✓ Branch 1 taken 1276 times.
✓ Branch 2 taken 11431 times.
✗ Branch 3 not taken.
12707 if (lost_gtids) lost_gtids->dbug_print("lost_gtids");
4949
2/2
✓ Branch 0 taken 12497 times.
✓ Branch 1 taken 210 times.
12707 if (need_lock) {
4950
1/2
✓ Branch 0 taken 12497 times.
✗ Branch 1 not taken.
12497 sid_lock->unlock();
4951
1/2
✓ Branch 0 taken 12497 times.
✗ Branch 1 not taken.
12497 mysql_mutex_unlock(&LOCK_index);
4952
2/4
✓ Branch 0 taken 12497 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12497 times.
✗ Branch 3 not taken.
12497 if (all_gtids != nullptr) mysql_mutex_unlock(&LOCK_log);
4953 }
4954 12707 filename_list.clear();
4955
3/8
✓ Branch 0 taken 12707 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12707 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 12707 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
12707 DBUG_PRINT("info", ("returning %d", error));
4956 12707 return error != 0 ? true : false;
4957 12707 }
4958
4959 /**
4960 Open a (new) binlog file.
4961
4962 - Open the log file and the index file. Register the new
4963 file name in it
4964 - When calling this when the file is in use, you must have a locks
4965 on LOCK_log and LOCK_index.
4966
4967 @retval
4968 0 ok
4969 @retval
4970 1 error
4971 */
4972
4973 84445 bool MYSQL_BIN_LOG::open_binlog(
4974 const char *log_name, const char *new_name, ulong max_size_arg,
4975 bool null_created_arg, bool need_lock_index, bool need_sid_lock,
4976 Format_description_log_event *extra_description_event,
4977 uint32 new_index_number) {
4978 // lock_index must be acquired *before* sid_lock.
4979
3/4
✓ Branch 0 taken 27126 times.
✓ Branch 1 taken 57319 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 27126 times.
84445 assert(need_sid_lock || !need_lock_index);
4980
1/2
✓ Branch 0 taken 84445 times.
✗ Branch 1 not taken.
84445 DBUG_TRACE;
4981
3/8
✓ Branch 0 taken 84445 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 84445 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 84445 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
84445 DBUG_PRINT("enter", ("base filename: %s", log_name));
4982
4983 84445 mysql_mutex_assert_owner(get_log_lock());
4984
4985
3/4
✓ Branch 0 taken 84445 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 84442 times.
84445 if (init_and_set_log_file_name(log_name, new_name, new_index_number)) {
4986
8/16
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 3 times.
✗ Branch 15 not taken.
3 LogErr(ERROR_LEVEL, ER_BINLOG_CANT_GENERATE_NEW_FILE_NAME);
4987 3 return true;
4988 }
4989
4990
3/8
✓ Branch 0 taken 84442 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 84442 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 84442 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
84442 DBUG_PRINT("info", ("generated filename: %s", log_file_name));
4991
4992
1/2
✓ Branch 0 taken 84442 times.
✗ Branch 1 not taken.
84442 if (open_purge_index_file(true) ||
4993
8/12
✓ Branch 0 taken 84442 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 84442 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 84442 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 84441 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 84440 times.
✓ Branch 9 taken 1 times.
✓ Branch 10 taken 6 times.
✓ Branch 11 taken 84435 times.
168882 register_create_index_entry(log_file_name) || sync_purge_index_file() ||
4994
3/4
✓ Branch 0 taken 84440 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 84435 times.
84440 DBUG_EVALUATE_IF("fault_injection_registering_index", 1, 0)) {
4995 /**
4996 @todo: although this was introduced to appease valgrind
4997 when injecting emulated faults using fault_injection_registering_index
4998 it may be good to consider what actually happens when
4999 open_purge_index_file succeeds but register or sync fails.
5000
5001 Perhaps we might need the code below in MYSQL_BIN_LOG::cleanup
5002 for "real life" purposes as well?
5003 */
5004
6/10
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 5 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 5 times.
✗ Branch 9 not taken.
6 DBUG_EXECUTE_IF("fault_injection_registering_index", {
5005 if (my_b_inited(&purge_index_file)) {
5006 end_io_cache(&purge_index_file);
5007 my_close(purge_index_file.file, MYF(0));
5008 }
5009 });
5010
5011
8/16
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 6 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 6 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 6 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 6 times.
✗ Branch 15 not taken.
6 LogErr(ERROR_LEVEL, ER_BINLOG_FAILED_TO_SYNC_INDEX_FILE_IN_OPEN);
5012 6 return true;
5013 }
5014
4/6
✓ Branch 0 taken 84435 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 84432 times.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
84435 DBUG_EXECUTE_IF("crash_create_non_critical_before_update_index",
5015 DBUG_SUICIDE(););
5016
5017 84432 write_error = false;
5018
5019 /* open the main log file */
5020
3/4
✓ Branch 0 taken 84432 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 84431 times.
84432 if (open(m_key_file_log, log_name, new_name, new_index_number)) {
5021
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 close_purge_index_file();
5022 1 return true; /* all warnings issued */
5023 }
5024
5025 84431 max_size = max_size_arg;
5026
5027 84431 bool write_file_name_to_index_file = false;
5028
5029 /* This must be before goto err. */
5030 #ifndef NDEBUG
5031 84431 binary_log_debug::debug_pretend_version_50034_in_binlog =
5032
1/2
✓ Branch 0 taken 84431 times.
✗ Branch 1 not taken.
84431 DBUG_EVALUATE_IF("pretend_version_50034_in_binlog", true, false);
5033 #endif
5034
1/2
✓ Branch 0 taken 84431 times.
✗ Branch 1 not taken.
84431 Format_description_log_event s;
5035
5036
1/2
✓ Branch 0 taken 84431 times.
✗ Branch 1 not taken.
84431 if (m_binlog_file->is_empty()) {
5037 /*
5038 The binary log file was empty (probably newly created)
5039 This is the normal case and happens when the user doesn't specify
5040 an extension for the binary log files.
5041 In this case we write a standard header to it.
5042 */
5043
2/4
✓ Branch 0 taken 84431 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 84431 times.
84431 if (m_binlog_file->write(pointer_cast<const uchar *>(BINLOG_MAGIC),
5044 BIN_LOG_HEADER_SIZE))
5045 goto err;
5046 84431 bytes_written += BIN_LOG_HEADER_SIZE;
5047 84431 write_file_name_to_index_file = true;
5048 }
5049
5050 /*
5051 don't set LOG_EVENT_BINLOG_IN_USE_F for the relay log
5052 */
5053
2/2
✓ Branch 0 taken 30662 times.
✓ Branch 1 taken 53769 times.
84431 if (!is_relay_log) {
5054 30662 s.common_header->flags |= LOG_EVENT_BINLOG_IN_USE_F;
5055 }
5056
5057
2/2
✓ Branch 0 taken 53769 times.
✓ Branch 1 taken 30662 times.
84431 if (is_relay_log) {
5058 /* relay-log */
5059
2/2
✓ Branch 0 taken 6642 times.
✓ Branch 1 taken 47127 times.
53769 if (relay_log_checksum_alg == binary_log::BINLOG_CHECKSUM_ALG_UNDEF) {
5060 /* inherit master's A descriptor if one has been received */
5061
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6642 times.
6642 if (opt_replica_sql_verify_checksum == 0)
5062 /* otherwise use slave's local preference of RL events verification */
5063 relay_log_checksum_alg = binary_log::BINLOG_CHECKSUM_ALG_OFF;
5064 else
5065 6642 relay_log_checksum_alg =
5066 6642 static_cast<enum_binlog_checksum_alg>(binlog_checksum_options);
5067 }
5068 }
5069
5070
2/4
✓ Branch 0 taken 84431 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 84431 times.
84431 if (!s.is_valid()) goto err;
5071 84431 s.dont_set_created = null_created_arg;
5072 /* Set LOG_EVENT_RELAY_LOG_F flag for relay log's FD */
5073
2/2
✓ Branch 0 taken 53769 times.
✓ Branch 1 taken 30662 times.
84431 if (is_relay_log) s.set_relay_log_event();
5074
2/4
✓ Branch 0 taken 84431 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 84431 times.
84431 if (write_event_to_binlog(&s)) goto err;
5075
5076 /*
5077 We need to revisit this code and improve it.
5078 See further comments in the mysqld.
5079 /Alfranio
5080 */
5081
3/4
✓ Branch 0 taken 84431 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 71717 times.
✓ Branch 3 taken 12714 times.
84431 if (current_thd) {
5082 71717 Checkable_rwlock *sid_lock = nullptr;
5083
1/2
✓ Branch 0 taken 71717 times.
✗ Branch 1 not taken.
71717 Gtid_set logged_gtids_binlog(global_sid_map, global_sid_lock);
5084 Gtid_set *previous_logged_gtids;
5085
5086
2/2
✓ Branch 0 taken 52279 times.
✓ Branch 1 taken 19438 times.
71717 if (is_relay_log) {
5087 52279 previous_logged_gtids = previous_gtid_set_relaylog;
5088 52279 sid_lock = previous_gtid_set_relaylog->get_sid_map()->get_sid_lock();
5089 } else {
5090 19438 previous_logged_gtids = &logged_gtids_binlog;
5091 19438 sid_lock = global_sid_lock;
5092 }
5093
5094
2/2
✓ Branch 0 taken 44592 times.
✓ Branch 1 taken 27125 times.
71717 if (need_sid_lock)
5095
1/2
✓ Branch 0 taken 44592 times.
✗ Branch 1 not taken.
44592 sid_lock->wrlock();
5096 else
5097
1/2
✓ Branch 0 taken 27125 times.
✗ Branch 1 not taken.
27125 sid_lock->assert_some_wrlock();
5098
5099
2/2
✓ Branch 0 taken 19438 times.
✓ Branch 1 taken 52279 times.
71717 if (!is_relay_log) {
5100 19438 const Gtid_set *executed_gtids = gtid_state->get_executed_gtids();
5101 const Gtid_set *gtids_only_in_table =
5102 19438 gtid_state->get_gtids_only_in_table();
5103 /* logged_gtids_binlog= executed_gtids - gtids_only_in_table */
5104
2/4
✓ Branch 0 taken 19438 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 19438 times.
19438 if (logged_gtids_binlog.add_gtid_set(executed_gtids) !=
5105 RETURN_STATUS_OK) {
5106 if (need_sid_lock) sid_lock->unlock();
5107 goto err;
5108 }
5109
1/2
✓ Branch 0 taken 19438 times.
✗ Branch 1 not taken.
19438 logged_gtids_binlog.remove_gtid_set(gtids_only_in_table);
5110 }
5111
3/10
✓ Branch 0 taken 71717 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 71717 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 71717 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
71717 DBUG_PRINT("info", ("Generating PREVIOUS_GTIDS for %s file.",
5112 is_relay_log ? "relaylog" : "binlog"));
5113
1/2
✓ Branch 0 taken 71717 times.
✗ Branch 1 not taken.
71717 Previous_gtids_log_event prev_gtids_ev(previous_logged_gtids);
5114
2/2
✓ Branch 0 taken 52279 times.
✓ Branch 1 taken 19438 times.
71717 if (is_relay_log) prev_gtids_ev.set_relay_log_event();
5115
3/4
✓ Branch 0 taken 44592 times.
✓ Branch 1 taken 27125 times.
✓ Branch 2 taken 44592 times.
✗ Branch 3 not taken.
71717 if (need_sid_lock) sid_lock->unlock();
5116
2/4
✓ Branch 0 taken 71717 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 71717 times.
71717 if (write_event_to_binlog(&prev_gtids_ev)) goto err;
5117
2/4
✓ Branch 0 taken 71717 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 71717 times.
✗ Branch 3 not taken.
71717 } else // !(current_thd)
5118 {
5119 /*
5120 If the slave was configured before server restart, the server will
5121 generate a new relay log file without having current_thd, but this
5122 new relay log file must have a PREVIOUS_GTIDS event as we now
5123 generate the PREVIOUS_GTIDS event always.
5124
5125 This is only needed for relay log files because the server will add
5126 the PREVIOUS_GTIDS of binary logs (when current_thd==NULL) after
5127 server's GTID initialization.
5128
5129 During server's startup at mysqld_main(), from the binary/relay log
5130 initialization point of view, it will:
5131 1) Call init_server_components() that will generate a new binary log
5132 file but won't write the PREVIOUS_GTIDS event yet;
5133 2) Initialize server's GTIDs;
5134 3) Write the binary log PREVIOUS_GTIDS;
5135 4) Call init_replica() in where the new relay log file will be created
5136 after initializing relay log's Retrieved_Gtid_Set;
5137 */
5138
2/2
✓ Branch 0 taken 1490 times.
✓ Branch 1 taken 11224 times.
12714 if (is_relay_log) {
5139 Sid_map *previous_gtid_sid_map =
5140 1490 previous_gtid_set_relaylog->get_sid_map();
5141 1490 Checkable_rwlock *sid_lock = previous_gtid_sid_map->get_sid_lock();
5142
5143
1/2
✓ Branch 0 taken 1490 times.
✗ Branch 1 not taken.
1490 if (need_sid_lock)
5144
1/2
✓ Branch 0 taken 1490 times.
✗ Branch 1 not taken.
1490 sid_lock->wrlock();
5145 else
5146 sid_lock->assert_some_wrlock(); /* purecov: inspected */
5147
5148
3/8
✓ Branch 0 taken 1490 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1490 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1490 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
1490 DBUG_PRINT("info", ("Generating PREVIOUS_GTIDS for relaylog file."));
5149
1/2
✓ Branch 0 taken 1490 times.
✗ Branch 1 not taken.
1490 Previous_gtids_log_event prev_gtids_ev(previous_gtid_set_relaylog);
5150 1490 prev_gtids_ev.set_relay_log_event();
5151
5152
2/4
✓ Branch 0 taken 1490 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1490 times.
✗ Branch 3 not taken.
1490 if (need_sid_lock) sid_lock->unlock();
5153
5154
2/4
✓ Branch 0 taken 1490 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1490 times.
1490 if (write_event_to_binlog(&prev_gtids_ev)) goto err;
5155
1/2
✓ Branch 0 taken 1490 times.
✗ Branch 1 not taken.
1490 }
5156 }
5157
2/2
✓ Branch 0 taken 5559 times.
✓ Branch 1 taken 78872 times.
84431 if (extra_description_event) {
5158 /*
5159 This is a relay log written to by the I/O slave thread.
5160 Write the event so that others can later know the format of this relay
5161 log.
5162 Note that this event is very close to the original event from the
5163 master (it has binlog version of the master, event types of the
5164 master), so this is suitable to parse the next relay log's event. It
5165 has been produced by
5166 Format_description_log_event::Format_description_log_event(char* buf,).
5167 Why don't we want to write the mi_description_event if this
5168 event is for format<4 (3.23 or 4.x): this is because in that case, the
5169 mi_description_event describes the data received from the
5170 master, but not the data written to the relay log (*conversion*),
5171 which is in format 4 (slave's).
5172 */
5173 /*
5174 Set 'created' to 0, so that in next relay logs this event does not
5175 trigger cleaning actions on the slave in
5176 Format_description_log_event::apply_event_impl().
5177 */
5178 5559 extra_description_event->created = 0;
5179 /* Don't set log_pos in event header */
5180 5559 extra_description_event->set_artificial_event();
5181
2/4
✓ Branch 0 taken 5559 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5559 times.
5559 if (binary_event_serialize(extra_description_event, m_binlog_file))
5182 goto err;
5183 5559 bytes_written += extra_description_event->common_header->data_written;
5184 }
5185
2/4
✓ Branch 0 taken 84431 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 84431 times.
84431 if (m_binlog_file->flush_and_sync()) goto err;
5186
5187
1/2
✓ Branch 0 taken 84431 times.
✗ Branch 1 not taken.
84431 if (write_file_name_to_index_file) {
5188
4/6
✓ Branch 0 taken 84431 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 84428 times.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
84431 DBUG_EXECUTE_IF("crash_create_critical_before_update_index",
5189 DBUG_SUICIDE(););
5190
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 84428 times.
84428 assert(my_b_inited(&index_file) != 0);
5191
5192 /*
5193 The new log file name is appended into crash safe index file after
5194 all the content of index file is copied into the crash safe index
5195 file. Then move the crash safe index file to index file.
5196 */
5197
4/6
✓ Branch 0 taken 84428 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 84427 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
84428 DBUG_EXECUTE_IF("simulate_disk_full_on_open_binlog",
5198 { DBUG_SET("+d,simulate_no_free_space_error"); });
5199
5/6
✓ Branch 0 taken 84428 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 84424 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 11 times.
✓ Branch 5 taken 84411 times.
168846 if (DBUG_EVALUATE_IF("fault_injection_updating_index", 1, 0) ||
5200
3/4
✓ Branch 0 taken 84418 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 84411 times.
84424 add_log_to_index((uchar *)log_file_name, strlen(log_file_name),
5201 need_lock_index)) {
5202
6/10
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 10 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
11 DBUG_EXECUTE_IF("simulate_disk_full_on_open_binlog", {
5203 DBUG_SET("-d,simulate_file_write_error");
5204 DBUG_SET("-d,simulate_no_free_space_error");
5205 DBUG_SET("-d,simulate_disk_full_on_open_binlog");
5206 });
5207 11 goto err;
5208 }
5209
5210
4/6
✓ Branch 0 taken 84411 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 84408 times.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
84411 DBUG_EXECUTE_IF("crash_create_after_update_index", DBUG_SUICIDE(););
5211 }
5212
5213 84408 atomic_log_state = LOG_OPENED;
5214 /*
5215 At every rotate memorize the last transaction counter state to use it as
5216 offset at logging the transaction logical timestamps.
5217 */
5218
1/2
✓ Branch 0 taken 84408 times.
✗ Branch 1 not taken.
84408 m_dependency_tracker.rotate();
5219
5220
1/2
✓ Branch 0 taken 84408 times.
✗ Branch 1 not taken.
84408 close_purge_index_file();
5221
5222
1/2
✓ Branch 0 taken 84408 times.
✗ Branch 1 not taken.
84408 update_binlog_end_pos();
5223 84408 return false;
5224
5225 11 err:
5226
2/4
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
11 if (is_inited_purge_index_file())
5227
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 purge_index_entry(nullptr, nullptr, need_lock_index);
5228
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 close_purge_index_file();
5229
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (binlog_error_action == ABORT_SERVER) {
5230 exec_binlog_error_action_abort(
5231 "Either disk is full, file system is read only or "
5232 "there was an encryption error while opening the binlog. "
5233 "Aborting the server.");
5234 } else {
5235
9/18
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 11 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 11 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 11 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 11 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 11 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 11 times.
✓ Branch 16 taken 11 times.
✗ Branch 17 not taken.
11 LogErr(ERROR_LEVEL, ER_BINLOG_CANT_USE_FOR_LOGGING,
5236 (new_name) ? new_name : name, errno);
5237
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 close(LOG_CLOSE_INDEX, false, need_lock_index);
5238 }
5239 11 return true;
5240 84429 }
5241
5242 /**
5243 Move crash safe index file to index file.
5244
5245 @param need_lock_index If true, LOCK_index will be acquired;
5246 otherwise it should already be held.
5247
5248 @retval 0 ok
5249 @retval -1 error
5250 */
5251 108993 int MYSQL_BIN_LOG::move_crash_safe_index_file_to_index_file(
5252 bool need_lock_index) {
5253 108993 int error = 0;
5254 108993 File fd = -1;
5255
1/2
✓ Branch 0 taken 108993 times.
✗ Branch 1 not taken.
108993 DBUG_TRACE;
5256 108993 int failure_trials = MYSQL_BIN_LOG::MAX_RETRIES_FOR_DELETE_RENAME_FAILURE;
5257 108993 bool file_rename_status = false, file_delete_status = false;
5258
1/2
✓ Branch 0 taken 108993 times.
✗ Branch 1 not taken.
108993 THD *thd = current_thd;
5259
5260
2/2
✓ Branch 0 taken 23364 times.
✓ Branch 1 taken 85629 times.
108993 if (need_lock_index)
5261
1/2
✓ Branch 0 taken 23364 times.
✗ Branch 1 not taken.
23364 mysql_mutex_lock(&LOCK_index);
5262 else
5263 85629 mysql_mutex_assert_owner(&LOCK_index);
5264
5265
1/2
✓ Branch 0 taken 108993 times.
✗ Branch 1 not taken.
108993 if (my_b_inited(&index_file)) {
5266
1/2
✓ Branch 0 taken 108993 times.
✗ Branch 1 not taken.
108993 end_io_cache(&index_file);
5267
2/4
✓ Branch 0 taken 108993 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 108993 times.
108993 if (mysql_file_close(index_file.file, MYF(0)) < 0) {
5268 error = -1;
5269 LogErr(ERROR_LEVEL, ER_BINLOG_FAILED_TO_CLOSE_INDEX_FILE_WHILE_REBUILDING,
5270 index_file_name);
5271 /*
5272 Delete Crash safe index file here and recover the binlog.index
5273 state(index_file io_cache) from old binlog.index content.
5274 */
5275 mysql_file_delete(key_file_binlog_index, crash_safe_index_file_name,
5276 MYF(0));
5277
5278 goto recoverable_err;
5279 }
5280
5281 /*
5282 Sometimes an outsider can lock index files for temporary viewing
5283 purpose. For eg: MEB locks binlog.index/relaylog.index to view
5284 the content of the file. During that small period of time, deletion
5285 of the file is not possible on some platforms(Eg: Windows)
5286 Server should retry the delete operation for few times instead of
5287 panicking immediately.
5288 */
5289
3/4
✓ Branch 0 taken 109005 times.
✓ Branch 1 taken 108984 times.
✓ Branch 2 taken 109005 times.
✗ Branch 3 not taken.
217989 while ((file_delete_status == false) && (failure_trials > 0)) {
5290
3/4
✓ Branch 0 taken 109005 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 108996 times.
109005 if (DBUG_EVALUATE_IF("force_index_file_delete_failure", 1, 0)) break;
5291
5292
9/12
✓ Branch 0 taken 108996 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 108981 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 12 times.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 15 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✓ Branch 11 taken 12 times.
108996 DBUG_EXECUTE_IF("simulate_index_file_delete_failure", {
5293 /* This simulation causes the delete to fail */
5294 static char first_char = index_file_name[0];
5295 index_file_name[0] = 0;
5296 sql_print_information("Retrying delete");
5297 if (failure_trials == 1) index_file_name[0] = first_char;
5298 };);
5299
1/2
✓ Branch 0 taken 108996 times.
✗ Branch 1 not taken.
108996 file_delete_status = !(mysql_file_delete(key_file_binlog_index,
5300 index_file_name, MYF(MY_WME)));
5301 108996 --failure_trials;
5302
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 108984 times.
108996 if (!file_delete_status) {
5303
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 my_sleep(1000);
5304 /* Clear the error before retrying. */
5305
2/4
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
12 if (failure_trials > 0) thd->clear_error();
5306 }
5307 }
5308
5309
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 108984 times.
108993 if (!file_delete_status) {
5310 9 error = -1;
5311
8/16
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 9 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 9 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 9 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 9 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 9 times.
✗ Branch 15 not taken.
9 LogErr(ERROR_LEVEL,
5312 ER_BINLOG_FAILED_TO_DELETE_INDEX_FILE_WHILE_REBUILDING,
5313 index_file_name);
5314 /*
5315 Delete Crash safe file index file here and recover the binlog.index
5316 state(index_file io_cache) from old binlog.index content.
5317 */
5318
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 mysql_file_delete(key_file_binlog_index, crash_safe_index_file_name,
5319 MYF(0));
5320
5321 9 goto recoverable_err;
5322 }
5323 }
5324
5325
4/6
✓ Branch 0 taken 108983 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 108977 times.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
108984 DBUG_EXECUTE_IF("crash_create_before_rename_index_file", DBUG_SUICIDE(););
5326 /*
5327 Sometimes an outsider can lock index files for temporary viewing
5328 purpose. For eg: MEB locks binlog.index/relaylog.index to view
5329 the content of the file. During that small period of time, rename
5330 of the file is not possible on some platforms(Eg: Windows)
5331 Server should retry the rename operation for few times instead of panicking
5332 immediately.
5333 */
5334 108977 failure_trials = MYSQL_BIN_LOG::MAX_RETRIES_FOR_DELETE_RENAME_FAILURE;
5335
3/4
✓ Branch 0 taken 108989 times.
✓ Branch 1 taken 108978 times.
✓ Branch 2 taken 108989 times.
✗ Branch 3 not taken.
217967 while ((file_rename_status == false) && (failure_trials > 0)) {
5336
9/12
✓ Branch 0 taken 108990 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 108975 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 12 times.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 15 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✓ Branch 11 taken 12 times.
108989 DBUG_EXECUTE_IF("simulate_crash_safe_index_file_rename_failure", {
5337 /* This simulation causes the rename to fail */
5338 static char first_char = index_file_name[0];
5339 index_file_name[0] = 0;
5340 sql_print_information("Retrying rename");
5341 if (failure_trials == 1) index_file_name[0] = first_char;
5342 };);
5343 108990 file_rename_status =
5344
1/2
✓ Branch 0 taken 108990 times.
✗ Branch 1 not taken.
108990 !(my_rename(crash_safe_index_file_name, index_file_name, MYF(MY_WME)));
5345 108990 --failure_trials;
5346
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 108978 times.
108990 if (!file_rename_status) {
5347
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 my_sleep(1000);
5348 /* Clear the error before retrying. */
5349
2/4
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
12 if (failure_trials > 0) thd->clear_error();
5350 }
5351 }
5352
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 108978 times.
108978 if (!file_rename_status) {
5353 error = -1;
5354 LogErr(ERROR_LEVEL, ER_BINLOG_FAILED_TO_RENAME_INDEX_FILE_WHILE_REBUILDING,
5355 index_file_name);
5356 goto fatal_err;
5357 }
5358
4/6
✓ Branch 0 taken 108978 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 108972 times.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
108978 DBUG_EXECUTE_IF("crash_create_after_rename_index_file", DBUG_SUICIDE(););
5359
5360 108972 recoverable_err:
5361
1/2
✓ Branch 0 taken 108981 times.
✗ Branch 1 not taken.
108981 if ((fd = mysql_file_open(key_file_binlog_index, index_file_name,
5362 108981 O_RDWR | O_CREAT, MYF(MY_WME))) < 0 ||
5363
4/8
✓ Branch 0 taken 108981 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 108981 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 108981 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 108981 times.
217962 mysql_file_sync(fd, MYF(MY_WME)) ||
5364
3/6
✓ Branch 0 taken 108981 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 108981 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 108981 times.
108981 init_io_cache_ext(&index_file, fd, IO_SIZE, READ_CACHE,
5365 mysql_file_seek(fd, 0L, MY_SEEK_END, MYF(0)), false,
5366 MYF(MY_WME | MY_WAIT_IF_FULL),
5367 key_file_binlog_index_cache)) {
5368 LogErr(ERROR_LEVEL, ER_BINLOG_FAILED_TO_OPEN_INDEX_FILE_AFTER_REBUILDING,
5369 index_file_name);
5370 goto fatal_err;
5371 }
5372
5373
3/4
✓ Branch 0 taken 23364 times.
✓ Branch 1 taken 85617 times.
✓ Branch 2 taken 23364 times.
✗ Branch 3 not taken.
108981 if (need_lock_index) mysql_mutex_unlock(&LOCK_index);
5374 108981 return error;
5375
5376 fatal_err:
5377 /*
5378 This situation is very very rare to happen (unless there is some serious
5379 memory related issues like OOM) and should be treated as fatal error.
5380 Hence it is better to bring down the server without respecting
5381 'binlog_error_action' value here.
5382 */
5383 exec_binlog_error_action_abort(
5384 "MySQL server failed to update the "
5385 "binlog.index file's content properly. "
5386 "It might not be in sync with available "
5387 "binlogs and the binlog.index file state is in "
5388 "unrecoverable state. Aborting the server.");
5389 /*
5390 Server is aborted in the above function.
5391 This is dead code to make compiler happy.
5392 */
5393 return error;
5394 108981 }
5395
5396 /**
5397 Append log file name to index file.
5398
5399 - To make crash safe, we copy all the content of index file
5400 to crash safe index file firstly and then append the log
5401 file name to the crash safe index file. Finally move the
5402 crash safe index file to index file.
5403
5404 @retval
5405 0 ok
5406 @retval
5407 -1 error
5408 */
5409 84424 int MYSQL_BIN_LOG::add_log_to_index(uchar *log_name, size_t log_name_len,
5410 bool need_lock_index) {
5411
1/2
✓ Branch 0 taken 84424 times.
✗ Branch 1 not taken.
84424 DBUG_TRACE;
5412
5413
2/4
✓ Branch 0 taken 84424 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 84424 times.
84424 if (open_crash_safe_index_file()) {
5414 LogErr(ERROR_LEVEL, ER_BINLOG_CANT_OPEN_TMP_INDEX,
5415 "MYSQL_BIN_LOG::add_log_to_index");
5416 goto err;
5417 }
5418
5419
3/4
✓ Branch 0 taken 84424 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 84423 times.
84424 if (copy_file(&index_file, &crash_safe_index_file, 0)) {
5420
8/16
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 1 times.
✗ Branch 15 not taken.
1 LogErr(ERROR_LEVEL, ER_BINLOG_CANT_COPY_INDEX_TO_TMP,
5421 "MYSQL_BIN_LOG::add_log_to_index");
5422 1 goto err;
5423 }
5424
5425
1/2
✓ Branch 0 taken 84423 times.
✗ Branch 1 not taken.
84423 if (my_b_write(&crash_safe_index_file, log_name, log_name_len) ||
5426
2/4
✓ Branch 0 taken 84423 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 84423 times.
✗ Branch 3 not taken.
84423 my_b_write(&crash_safe_index_file, pointer_cast<const uchar *>("\n"),
5427 84423 1) ||
5428
4/8
✓ Branch 0 taken 84423 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 84423 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 84423 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 84423 times.
253269 flush_io_cache(&crash_safe_index_file) ||
5429
2/4
✓ Branch 0 taken 84423 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 84423 times.
84423 mysql_file_sync(crash_safe_index_file.file, MYF(MY_WME))) {
5430 LogErr(ERROR_LEVEL, ER_BINLOG_CANT_APPEND_LOG_TO_TMP_INDEX, log_name);
5431 goto err;
5432 }
5433
5434
2/4
✓ Branch 0 taken 84423 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 84423 times.
84423 if (close_crash_safe_index_file()) {
5435 LogErr(ERROR_LEVEL, ER_BINLOG_CANT_CLOSE_TMP_INDEX,
5436 "MYSQL_BIN_LOG::add_log_to_index");
5437 goto err;
5438 }
5439
5440
3/4
✓ Branch 0 taken 84417 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 84411 times.
84423 if (move_crash_safe_index_file_to_index_file(need_lock_index)) {
5441
8/16
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 6 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 6 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 6 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 6 times.
✗ Branch 15 not taken.
6 LogErr(ERROR_LEVEL, ER_BINLOG_CANT_MOVE_TMP_TO_INDEX,
5442 "MYSQL_BIN_LOG::add_log_to_index");
5443 6 goto err;
5444 }
5445
5446 84411 return 0;
5447
5448 7 err:
5449 7 return -1;
5450 84418 }
5451
5452 1691851 int MYSQL_BIN_LOG::get_current_log(LOG_INFO *linfo,
5453 bool need_lock_log /*true*/) {
5454
2/2
✓ Branch 0 taken 105695 times.
✓ Branch 1 taken 1586156 times.
1691851 if (need_lock_log) mysql_mutex_lock(&LOCK_log);
5455 1691851 int ret = raw_get_current_log(linfo);
5456
2/2
✓ Branch 0 taken 105695 times.
✓ Branch 1 taken 1586156 times.
1691851 if (need_lock_log) mysql_mutex_unlock(&LOCK_log);
5457 1691851 return ret;
5458 }
5459
5460 1692343 int MYSQL_BIN_LOG::raw_get_current_log(LOG_INFO *linfo) {
5461 1692343 strmake(linfo->log_file_name, log_file_name,
5462 sizeof(linfo->log_file_name) - 1);
5463 1692343 linfo->pos = m_binlog_file->position();
5464 1692343 linfo->encrypted_header_size = m_binlog_file->get_encrypted_header_size();
5465 1692343 return 0;
5466 }
5467
5468 8637 static bool check_write_error_code(uint error_code) {
5469
2/2
✓ Branch 0 taken 8506 times.
✓ Branch 1 taken 15 times.
8521 return error_code == ER_TRANS_CACHE_FULL ||
5470
5/6
✓ Branch 0 taken 8521 times.
✓ Branch 1 taken 116 times.
✓ Branch 2 taken 8430 times.
✓ Branch 3 taken 76 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 8430 times.
17158 error_code == ER_STMT_CACHE_FULL || error_code == ER_ERROR_ON_WRITE ||
5471 8637 error_code == ER_BINLOG_LOGGING_IMPOSSIBLE;
5472 }
5473
5474 8904 bool MYSQL_BIN_LOG::check_write_error(const THD *thd) {
5475
1/2
✓ Branch 0 taken 8905 times.
✗ Branch 1 not taken.
8904 DBUG_TRACE;
5476
5477
3/4
✓ Branch 0 taken 8904 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3700 times.
✓ Branch 3 taken 5204 times.
8905 if (!thd->is_error()) return false;
5478
5479 5204 bool checked = check_write_error_code(thd->get_stmt_da()->mysql_errno());
5480
5481
2/2
✓ Branch 0 taken 4997 times.
✓ Branch 1 taken 207 times.
5204 if (!checked) {
5482 /* Check all conditions for one that matches the expected error */
5483 const Sql_condition *err;
5484 Diagnostics_area::Sql_condition_iterator it =
5485
1/2
✓ Branch 0 taken 4997 times.
✗ Branch 1 not taken.
4997 thd->get_stmt_da()->sql_conditions();
5486
6/8
✓ Branch 0 taken 8430 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3433 times.
✓ Branch 3 taken 4997 times.
✓ Branch 4 taken 3433 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3433 times.
✓ Branch 7 taken 4997 times.
8430 while ((err = it++) != nullptr && !checked) {
5487 3433 checked = check_write_error_code(err->mysql_errno());
5488 }
5489 }
5490
3/10
✓ Branch 0 taken 5204 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5205 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 5205 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
5204 DBUG_PRINT("return", ("checked: %s", YESNO(checked)));
5491 5205 return checked;
5492 8905 }
5493
5494 97 void MYSQL_BIN_LOG::report_cache_write_error(THD *thd, bool is_transactional) {
5495
1/2
✓ Branch 0 taken 97 times.
✗ Branch 1 not taken.
97 DBUG_TRACE;
5496
5497 97 write_error = true;
5498
5499
2/4
✓ Branch 0 taken 97 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 97 times.
97 if (check_write_error(thd)) return;
5500
5501
3/4
✓ Branch 0 taken 97 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 60 times.
✓ Branch 3 taken 37 times.
97 if (my_errno() == EFBIG) {
5502
2/2
✓ Branch 0 taken 53 times.
✓ Branch 1 taken 7 times.
60 if (is_transactional) {
5503
1/2
✓ Branch 0 taken 53 times.
✗ Branch 1 not taken.
53 my_error(ER_TRANS_CACHE_FULL, MYF(MY_WME));
5504 } else {
5505
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 my_error(ER_STMT_CACHE_FULL, MYF(MY_WME));
5506 }
5507 } else {
5508 char errbuf[MYSYS_STRERROR_SIZE];
5509
1/2
✓ Branch 0 taken 37 times.
✗ Branch 1 not taken.
37 my_error(ER_ERROR_ON_WRITE, MYF(MY_WME), name, errno,
5510
1/2
✓ Branch 0 taken 37 times.
✗ Branch 1 not taken.
37 my_strerror(errbuf, sizeof(errbuf), errno));
5511 }
5512
1/2
✓ Branch 0 taken 97 times.
✗ Branch 1 not taken.
97 }
5513
5514 10499818 static int compare_log_name(const char *log_1, const char *log_2) {
5515 10499818 const char *log_1_basename = log_1 + dirname_length(log_1);
5516 10499809 const char *log_2_basename = log_2 + dirname_length(log_2);
5517
5518 10499817 return strcmp(log_1_basename, log_2_basename);
5519 }
5520
5521 /**
5522 Find the position in the log-index-file for the given log name.
5523
5524 @param[out] linfo The found log file name will be stored here, along
5525 with the byte offset of the next log file name in the index file.
5526 @param log_name Filename to find in the index file, or NULL if we
5527 want to read the first entry.
5528 @param need_lock_index If false, this function acquires LOCK_index;
5529 otherwise the lock should already be held by the caller.
5530
5531 @note
5532 On systems without the truncate function the file will end with one or
5533 more empty lines. These will be ignored when reading the file.
5534
5535 @retval
5536 0 ok
5537 @retval
5538 LOG_INFO_EOF End of log-index-file found
5539 @retval
5540 LOG_INFO_IO Got IO error while reading file
5541 */
5542
5543 255109 int MYSQL_BIN_LOG::find_log_pos(LOG_INFO *linfo, const char *log_name,
5544 bool need_lock_index) {
5545 255109 int error = 0;
5546 255109 char *full_fname = linfo->log_file_name;
5547 char full_log_name[FN_REFLEN], fname[FN_REFLEN];
5548
1/2
✓ Branch 0 taken 255109 times.
✗ Branch 1 not taken.
255109 DBUG_TRACE;
5549 255109 full_log_name[0] = full_fname[0] = 0;
5550
5551 /*
5552 Mutex needed because we need to make sure the file pointer does not
5553 move from under our feet
5554 */
5555
2/2
✓ Branch 0 taken 89390 times.
✓ Branch 1 taken 165719 times.
255109 if (need_lock_index)
5556
1/2
✓ Branch 0 taken 89390 times.
✗ Branch 1 not taken.
89390 mysql_mutex_lock(&LOCK_index);
5557 else
5558 165719 mysql_mutex_assert_owner(&LOCK_index);
5559
5560
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 255106 times.
255109 if (!my_b_inited(&index_file)) {
5561 3 error = LOG_INFO_IO;
5562 3 goto end;
5563 }
5564
5565 // extend relative paths for log_name to be searched
5566
2/2
✓ Branch 0 taken 95249 times.
✓ Branch 1 taken 159857 times.
255106 if (log_name) {
5567
2/4
✓ Branch 0 taken 95249 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 95249 times.
95249 if (normalize_binlog_name(full_log_name, log_name, is_relay_log)) {
5568 error = LOG_INFO_EOF;
5569 goto end;
5570 }
5571 }
5572
5573
3/10
✓ Branch 0 taken 255106 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 255106 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 255106 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
255106 DBUG_PRINT("enter", ("log_name: %s, full_log_name: %s",
5574 log_name ? log_name : "NULL", full_log_name));
5575
5576 /* As the file is flushed, we can't get an error here */
5577
1/2
✓ Branch 0 taken 255106 times.
✗ Branch 1 not taken.
255106 my_b_seek(&index_file, (my_off_t)0);
5578
5579 for (;;) {
5580 size_t length;
5581 2430186 my_off_t offset = my_b_tell(&index_file);
5582
5583
3/4
✓ Branch 0 taken 2430186 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 2430172 times.
2430186 DBUG_EXECUTE_IF("simulate_find_log_pos_error", error = LOG_INFO_EOF;
5584 break;);
5585 /* If we get 0 or 1 characters, this is the end of the file */
5586
3/4
✓ Branch 0 taken 2430186 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 20402 times.
✓ Branch 3 taken 2409784 times.
2430186 if ((length = my_b_gets(&index_file, fname, FN_REFLEN)) <= 1) {
5587 /* Did not find the given entry; Return not found or error */
5588
1/2
✓ Branch 0 taken 20402 times.
✗ Branch 1 not taken.
20402 error = !index_file.error ? LOG_INFO_EOF : LOG_INFO_IO;
5589 20402 break;
5590 }
5591
5592 // extend relative paths and match against full path
5593
2/4
✓ Branch 0 taken 2409784 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2409784 times.
2409784 if (normalize_binlog_name(full_fname, fname, is_relay_log)) {
5594 error = LOG_INFO_EOF;
5595 break;
5596 }
5597 // if the log entry matches, null string matching anything
5598
7/8
✓ Branch 0 taken 2255047 times.
✓ Branch 1 taken 154737 times.
✓ Branch 2 taken 2255047 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 79967 times.
✓ Branch 5 taken 2175080 times.
✓ Branch 6 taken 234704 times.
✓ Branch 7 taken 2175080 times.
2409784 if (!log_name || !compare_log_name(full_fname, full_log_name)) {
5599
3/8
✓ Branch 0 taken 234704 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 234704 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 234704 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
234704 DBUG_PRINT("info", ("Found log file entry"));
5600 234704 linfo->index_file_start_offset = offset;
5601 234704 linfo->index_file_offset = my_b_tell(&index_file);
5602 234704 break;
5603 }
5604 2175080 linfo->entry_index++;
5605 2175080 }
5606
5607 255109 end:
5608
3/4
✓ Branch 0 taken 89390 times.
✓ Branch 1 taken 165719 times.
✓ Branch 2 taken 89390 times.
✗ Branch 3 not taken.
255109 if (need_lock_index) mysql_mutex_unlock(&LOCK_index);
5609 255109 return error;
5610 255109 }
5611
5612 /**
5613 Find the position in the log-index-file for the given log name.
5614
5615 @param[out] linfo The filename will be stored here, along with the
5616 byte offset of the next filename in the index file.
5617
5618 @param need_lock_index If true, LOCK_index will be acquired;
5619 otherwise it should already be held by the caller.
5620
5621 @note
5622 - Before calling this function, one has to call find_log_pos()
5623 to set up 'linfo'
5624 - Mutex needed because we need to make sure the file pointer does not move
5625 from under our feet
5626
5627 @retval 0 ok
5628 @retval LOG_INFO_EOF End of log-index-file found
5629 @retval LOG_INFO_IO Got IO error while reading file
5630 */
5631 547489 int MYSQL_BIN_LOG::find_next_log(LOG_INFO *linfo, bool need_lock_index) {
5632 547489 int error = 0;
5633 size_t length;
5634 char fname[FN_REFLEN];
5635 547489 char *full_fname = linfo->log_file_name;
5636
5637
2/2
✓ Branch 0 taken 248441 times.
✓ Branch 1 taken 299048 times.
547489 if (need_lock_index)
5638
1/2
✓ Branch 0 taken 248441 times.
✗ Branch 1 not taken.
248441 mysql_mutex_lock(&LOCK_index);
5639 else
5640 299048 mysql_mutex_assert_owner(&LOCK_index);
5641
5642
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 547489 times.
547489 if (!my_b_inited(&index_file)) {
5643 error = LOG_INFO_IO;
5644 goto err;
5645 }
5646 /* As the file is flushed, we can't get an error here */
5647
1/2
✓ Branch 0 taken 547489 times.
✗ Branch 1 not taken.
547489 my_b_seek(&index_file, linfo->index_file_offset);
5648
5649 547489 linfo->index_file_start_offset = linfo->index_file_offset;
5650
3/4
✓ Branch 0 taken 547489 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 82759 times.
✓ Branch 3 taken 464730 times.
547489 if ((length = my_b_gets(&index_file, fname, FN_REFLEN)) <= 1) {
5651
1/2
✓ Branch 0 taken 82759 times.
✗ Branch 1 not taken.
82759 error = !index_file.error ? LOG_INFO_EOF : LOG_INFO_IO;
5652 82759 goto err;
5653 }
5654
5655
1/2
✓ Branch 0 taken 464730 times.
✗ Branch 1 not taken.
464730 if (fname[0] != 0) {
5656
2/4
✓ Branch 0 taken 464730 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 464730 times.
464730 if (normalize_binlog_name(full_fname, fname, is_relay_log)) {
5657 error = LOG_INFO_EOF;
5658 goto err;
5659 }
5660 464730 length = strlen(full_fname);
5661 }
5662
5663 464730 linfo->index_file_offset = my_b_tell(&index_file);
5664
5665 547489 err:
5666
3/4
✓ Branch 0 taken 248441 times.
✓ Branch 1 taken 299048 times.
✓ Branch 2 taken 248441 times.
✗ Branch 3 not taken.
547489 if (need_lock_index) mysql_mutex_unlock(&LOCK_index);
5667 547489 return error;
5668 }
5669
5670 /**
5671 Find the relay log name following the given name from relay log index file.
5672
5673 @param[in,out] log_name The name is full path name.
5674
5675 @return return 0 if it finds next relay log. Otherwise return the error code.
5676 */
5677 int MYSQL_BIN_LOG::find_next_relay_log(char log_name[FN_REFLEN + 1]) {
5678 LOG_INFO info;
5679 int error;
5680 char relative_path_name[FN_REFLEN + 1];
5681
5682 if (fn_format(relative_path_name, log_name + dirname_length(log_name),
5683 mysql_data_home, "", 0) == NullS)
5684 return 1;
5685
5686 mysql_mutex_lock(&LOCK_index);
5687
5688 error = find_log_pos(&info, relative_path_name, false);
5689 if (error == 0) {
5690 error = find_next_log(&info, false);
5691 if (error == 0) strcpy(log_name, info.log_file_name);
5692 }
5693
5694 mysql_mutex_unlock(&LOCK_index);
5695 return error;
5696 }
5697
5698 16920 std::pair<int, std::list<std::string>> MYSQL_BIN_LOG::get_log_index(
5699 bool need_lock_index) {
5700
1/2
✓ Branch 0 taken 16920 times.
✗ Branch 1 not taken.
16920 DBUG_TRACE;
5701 16920 LOG_INFO log_info;
5702
5703
2/2
✓ Branch 0 taken 4213 times.
✓ Branch 1 taken 12707 times.
16920 if (need_lock_index)
5704
1/2
✓ Branch 0 taken 4213 times.
✗ Branch 1 not taken.
4213 mysql_mutex_lock(&LOCK_index);
5705 else
5706 12707 mysql_mutex_assert_owner(&LOCK_index);
5707
5708 16920 std::list<std::string> filename_list;
5709 16920 int error = 0;
5710 16920 for (error =
5711
1/2
✓ Branch 0 taken 16920 times.
✗ Branch 1 not taken.
16920 this->find_log_pos(&log_info, nullptr, false /*need_lock_index*/);
5712
2/2
✓ Branch 0 taken 229023 times.
✓ Branch 1 taken 16920 times.
245943 error == 0;
5713 229023 error = this->find_next_log(&log_info, false /*need_lock_index*/)) {
5714
3/6
✓ Branch 0 taken 229023 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 229023 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 229023 times.
✗ Branch 5 not taken.
229023 filename_list.push_back(std::string(log_info.log_file_name));
5715 }
5716
5717
3/4
✓ Branch 0 taken 4213 times.
✓ Branch 1 taken 12707 times.
✓ Branch 2 taken 4213 times.
✗ Branch 3 not taken.
16920 if (need_lock_index) mysql_mutex_unlock(&LOCK_index);
5718
5719
1/2
✓ Branch 0 taken 16920 times.
✗ Branch 1 not taken.
33840 return std::make_pair(error, filename_list);
5720 16920 }
5721
5722 /**
5723 Removes files, as part of a RESET MASTER or RESET SLAVE statement,
5724 by deleting all logs referred to in the index file and the index
5725 file. Then, it creates a new index file and a new log file.
5726
5727 The new index file will only contain the new log file.
5728
5729 @param thd Thread
5730 @param delete_only If true, do not create a new index file and
5731 a new log file.
5732
5733 @note
5734 If not called from slave thread, write start event to new log
5735
5736 @retval
5737 0 ok
5738 @retval
5739 1 error
5740 */
5741 29987 bool MYSQL_BIN_LOG::reset_logs(THD *thd, bool delete_only) {
5742 29987 LOG_INFO linfo;
5743 29987 bool error = false;
5744 int err;
5745 29987 const char *save_name = nullptr;
5746 29987 Checkable_rwlock *sid_lock = nullptr;
5747
1/2
✓ Branch 0 taken 29987 times.
✗ Branch 1 not taken.
29987 DBUG_TRACE;
5748
5749 /*
5750 Flush logs for storage engines, so that the last transaction
5751 is persisted inside storage engines.
5752 */
5753
2/4
✓ Branch 0 taken 29987 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 29987 times.
29987 assert(!thd->is_log_reset());
5754
1/2
✓ Branch 0 taken 29987 times.
✗ Branch 1 not taken.
29987 thd->set_log_reset();
5755
2/4
✓ Branch 0 taken 29987 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 29987 times.
29987 if (ha_flush_logs()) {
5756 thd->clear_log_reset();
5757 return true;
5758 }
5759
1/2
✓ Branch 0 taken 29987 times.
✗ Branch 1 not taken.
29987 thd->clear_log_reset();
5760
5761
1/2
✓ Branch 0 taken 29987 times.
✗ Branch 1 not taken.
29987 ha_reset_logs(thd);
5762
5763 /*
5764 We need to get both locks to be sure that no one is trying to
5765 write to the index log file.
5766 */
5767
1/2
✓ Branch 0 taken 29987 times.
✗ Branch 1 not taken.
29987 mysql_mutex_lock(&LOCK_log);
5768
1/2
✓ Branch 0 taken 29987 times.
✗ Branch 1 not taken.
29987 mysql_mutex_lock(&LOCK_index);
5769
5770
2/2
✓ Branch 0 taken 20220 times.
✓ Branch 1 taken 9767 times.
29987 if (is_relay_log)
5771 20220 sid_lock = previous_gtid_set_relaylog->get_sid_map()->get_sid_lock();
5772 else
5773 9767 sid_lock = global_sid_lock;
5774
1/2
✓ Branch 0 taken 29987 times.
✗ Branch 1 not taken.
29987 sid_lock->wrlock();
5775
5776 /* Save variables so that we can reopen the log */
5777 29987 save_name = name;
5778 29987 name = nullptr; // Protect against free
5779
1/2
✓ Branch 0 taken 29987 times.
✗ Branch 1 not taken.
29987 close(LOG_CLOSE_TO_BE_OPENED, false /*need_lock_log=false*/,
5780 false /*need_lock_index=false*/);
5781
5782 /*
5783 First delete all old log files and then update the index file.
5784 As we first delete the log files and do not use sort of logging,
5785 a crash may lead to an inconsistent state where the index has
5786 references to non-existent files.
5787
5788 We need to invert the steps and use the purge_index_file methods
5789 in order to make the operation safe.
5790 */
5791
5792
3/4
✓ Branch 0 taken 29987 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 29978 times.
29987 if ((err = find_log_pos(&linfo, NullS, false /*need_lock_index=false*/)) !=
5793 0) {
5794 9 uint errcode = purge_log_get_error_code(err);
5795
8/16
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 9 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 9 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 9 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 9 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 9 times.
✗ Branch 15 not taken.
9 LogErr(ERROR_LEVEL, ER_BINLOG_CANT_LOCATE_OLD_BINLOG_OR_RELAY_LOG_FILES);
5796
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 my_error(errcode, MYF(0));
5797 9 error = true;
5798 9 goto err;
5799 }
5800
5801 for (;;) {
5802
3/4
✓ Branch 0 taken 46247 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 46237 times.
46247 if ((error = my_delete_allow_opened(linfo.log_file_name, MYF(0))) != 0) {
5803
3/4
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 3 times.
10 if (my_errno() == ENOENT) {
5804 21 push_warning_printf(
5805
2/4
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
7 current_thd, Sql_condition::SL_WARNING, ER_LOG_PURGE_NO_FILE,
5806
2/4
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
7 ER_THD(current_thd, ER_LOG_PURGE_NO_FILE), linfo.log_file_name);
5807
8/16
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 7 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 7 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 7 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 7 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 7 times.
✗ Branch 15 not taken.
7 LogErr(INFORMATION_LEVEL, ER_BINLOG_CANT_DELETE_FILE,
5808 linfo.log_file_name);
5809
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 set_my_errno(0);
5810 7 error = false;
5811 } else {
5812
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
3 push_warning_printf(current_thd, Sql_condition::SL_WARNING,
5813 ER_BINLOG_PURGE_FATAL_ERR,
5814 "a problem with deleting %s; "
5815 "consider examining correspondence "
5816 "of your binlog index file "
5817 "to the actual binlog files",
5818 linfo.log_file_name);
5819
8/16
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 3 times.
✗ Branch 15 not taken.
3 LogErr(ERROR_LEVEL, ER_BINLOG_CANT_DELETE_FILE, linfo.log_file_name);
5820
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 my_error(ER_BINLOG_PURGE_FATAL_ERR, MYF(0));
5821 3 error = true;
5822 3 goto err;
5823 }
5824 }
5825
3/4
✓ Branch 0 taken 46244 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 29975 times.
✓ Branch 3 taken 16269 times.
46244 if (find_next_log(&linfo, false /*need_lock_index=false*/)) break;
5826 }
5827
5828 /* Start logging with a new file */
5829
1/2
✓ Branch 0 taken 29975 times.
✗ Branch 1 not taken.
29975 close(LOG_CLOSE_INDEX | LOG_CLOSE_TO_BE_OPENED, false /*need_lock_log=false*/,
5830 false /*need_lock_index=false*/);
5831
3/4
✓ Branch 0 taken 29975 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 29972 times.
29975 if ((error = my_delete_allow_opened(index_file_name,
5832 MYF(0)))) // Reset (open will update)
5833 {
5834
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
3 if (my_errno() == ENOENT) {
5835 push_warning_printf(
5836 current_thd, Sql_condition::SL_WARNING, ER_LOG_PURGE_NO_FILE,
5837 ER_THD(current_thd, ER_LOG_PURGE_NO_FILE), index_file_name);
5838 LogErr(INFORMATION_LEVEL, ER_BINLOG_CANT_DELETE_FILE, index_file_name);
5839 set_my_errno(0);
5840 error = false;
5841 } else {
5842
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 push_warning_printf(current_thd, Sql_condition::SL_WARNING,
5843 ER_BINLOG_PURGE_FATAL_ERR,
5844 "a problem with deleting %s; "
5845 "consider examining correspondence "
5846 "of your binlog index file "
5847 "to the actual binlog files",
5848
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 index_file_name);
5849
8/16
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 3 times.
✗ Branch 15 not taken.
3 LogErr(ERROR_LEVEL, ER_BINLOG_CANT_DELETE_FILE, index_file_name);
5850
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 my_error(ER_BINLOG_PURGE_FATAL_ERR, MYF(0));
5851 3 error = true;
5852 3 goto err;
5853 }
5854 }
5855
5/8
✓ Branch 0 taken 29972 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 29969 times.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 3 times.
29972 DBUG_EXECUTE_IF("wait_for_kill_gtid_state_clear", {
5856 const char action[] = "now WAIT_FOR kill_gtid_state_clear";
5857 assert(!debug_sync_set_action(thd, STRING_WITH_LEN(action)));
5858 };);
5859
5860 /*
5861 For relay logs we clear the gtid state associated per channel(i.e rli)
5862 in the purge_relay_logs()
5863 */
5864
2/2
✓ Branch 0 taken 9758 times.
✓ Branch 1 taken 20214 times.
29972 if (!is_relay_log) {
5865
3/4
✓ Branch 0 taken 9758 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 9752 times.
9758 if (gtid_state->clear(thd)) {
5866 6 error = true;
5867 }
5868 /*
5869 Don't clear global_sid_map because gtid_state->clear() above didn't
5870 touched owned_gtids GTID set.
5871 */
5872
4/6
✓ Branch 0 taken 9752 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 9752 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 9752 times.
9758 error = error || gtid_state->init();
5873 }
5874
5875
2/2
✓ Branch 0 taken 27126 times.
✓ Branch 1 taken 2846 times.
29972 if (!delete_only) {
5876
2/4
✓ Branch 0 taken 27126 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 27126 times.
✗ Branch 3 not taken.
27126 if (!open_index_file(index_file_name, nullptr,
5877 false /*need_lock_index=false*/))
5878 27126 error = open_binlog(save_name, nullptr, max_size, false,
5879 false /*need_lock_index=false*/,
5880 false /*need_sid_lock=false*/, nullptr,
5881
5/6
✓ Branch 0 taken 27126 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 27125 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 27119 times.
27126 thd->lex->next_binlog_file_nr) ||
5882 error;
5883 }
5884 /* String has been duplicated, free old file-name */
5885
2/2
✓ Branch 0 taken 2847 times.
✓ Branch 1 taken 27125 times.
29972 if (name != nullptr) {
5886
1/2
✓ Branch 0 taken 27125 times.
✗ Branch 1 not taken.
27125 my_free(const_cast<char *>(save_name));
5887 27125 save_name = nullptr;
5888 }
5889
5890 2847 err:
5891
2/2
✓ Branch 0 taken 2862 times.
✓ Branch 1 taken 27125 times.
29987 if (name == nullptr)
5892 2862 name = const_cast<char *>(save_name); // restore old file-name
5893
1/2
✓ Branch 0 taken 29987 times.
✗ Branch 1 not taken.
29987 sid_lock->unlock();
5894
1/2
✓ Branch 0 taken 29987 times.
✗ Branch 1 not taken.
29987 count_binlog_space(false);
5895
1/2
✓ Branch 0 taken 29987 times.
✗ Branch 1 not taken.
29987 mysql_mutex_unlock(&LOCK_index);
5896
1/2
✓ Branch 0 taken 29987 times.
✗ Branch 1 not taken.
29987 mysql_mutex_unlock(&LOCK_log);
5897 29987 return error;
5898 29987 }
5899
5900 /**
5901 Set the name of crash safe index file.
5902
5903 @retval
5904 0 ok
5905 @retval
5906 1 error
5907 */
5908 84650 int MYSQL_BIN_LOG::set_crash_safe_index_file_name(const char *base_file_name) {
5909 84650 int error = 0;
5910
1/2
✓ Branch 0 taken 84650 times.
✗ Branch 1 not taken.
84650 DBUG_TRACE;
5911
1/2
✓ Branch 0 taken 84650 times.
✗ Branch 1 not taken.
84650 if (fn_format(crash_safe_index_file_name, base_file_name, mysql_data_home,
5912 ".index_crash_safe",
5913
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 84650 times.
84650 MYF(MY_UNPACK_FILENAME | MY_SAFE_PATH | MY_REPLACE_EXT)) ==
5914 nullptr) {
5915 error = 1;
5916 LogErr(ERROR_LEVEL, ER_BINLOG_CANT_SET_TMP_INDEX_NAME);
5917 }
5918 84650 return error;
5919 84650 }
5920
5921 /**
5922 Open a (new) crash safe index file.
5923
5924 @note
5925 The crash safe index file is a special file
5926 used for guaranteeing index file crash safe.
5927 @retval
5928 0 ok
5929 @retval
5930 1 error
5931 */
5932 108997 int MYSQL_BIN_LOG::open_crash_safe_index_file() {
5933 108997 int error = 0;
5934 108997 File file = -1;
5935
5936
1/2
✓ Branch 0 taken 108997 times.
✗ Branch 1 not taken.
108997 DBUG_TRACE;
5937
5938
1/2
✓ Branch 0 taken 108997 times.
✗ Branch 1 not taken.
108997 if (!my_b_inited(&crash_safe_index_file)) {
5939 108997 myf flags = MY_WME | MY_NABP | MY_WAIT_IF_FULL;
5940
2/2
✓ Branch 0 taken 78120 times.
✓ Branch 1 taken 30877 times.
108997 if (is_relay_log) flags = flags | MY_REPORT_WAITING_IF_FULL;
5941
5942
1/2
✓ Branch 0 taken 108997 times.
✗ Branch 1 not taken.
108997 if ((file = my_open(crash_safe_index_file_name, O_RDWR | O_CREAT,
5943
2/4
✓ Branch 0 taken 108997 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 108997 times.
217994 MYF(MY_WME))) < 0 ||
5944
2/4
✓ Branch 0 taken 108997 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 108997 times.
108997 init_io_cache(&crash_safe_index_file, file, IO_SIZE, WRITE_CACHE, 0,
5945 false, flags)) {
5946 error = 1;
5947 LogErr(ERROR_LEVEL, ER_BINLOG_FAILED_TO_OPEN_TEMPORARY_INDEX_FILE);
5948 }
5949 }
5950 108997 return error;
5951 108997 }
5952
5953 /**
5954 Close the crash safe index file.
5955
5956 @note
5957 The crash safe file is just closed, is not deleted.
5958 Because it is moved to index file later on.
5959 @retval
5960 0 ok
5961 @retval
5962 1 error
5963 */
5964 108996 int MYSQL_BIN_LOG::close_crash_safe_index_file() {
5965 108996 int error = 0;
5966
5967
1/2
✓ Branch 0 taken 108996 times.
✗ Branch 1 not taken.
108996 DBUG_TRACE;
5968
5969
1/2
✓ Branch 0 taken 108996 times.
✗ Branch 1 not taken.
108996 if (my_b_inited(&crash_safe_index_file)) {
5970
1/2
✓ Branch 0 taken 108996 times.
✗ Branch 1 not taken.
108996 end_io_cache(&crash_safe_index_file);
5971
1/2
✓ Branch 0 taken 108996 times.
✗ Branch 1 not taken.
108996 error = my_close(crash_safe_index_file.file, MYF(0));
5972 }
5973 108996 crash_safe_index_file = IO_CACHE();
5974
5975 108996 return error;
5976 108996 }
5977
5978 /**
5979 Remove logs from index file.
5980
5981 - To make it crash safe, we copy the content of the index file
5982 from index_file_start_offset recorded in log_info to a
5983 crash safe index file first and then move the crash
5984 safe index file to the index file.
5985
5986 @param log_info Store here the found log file name and
5987 position to the NEXT log file name in
5988 the index file.
5989
5990 @param need_update_threads If we want to update the log coordinates
5991 of all threads. False for relay logs,
5992 true otherwise.
5993
5994 @retval
5995 0 ok
5996 @retval
5997 LOG_INFO_IO Got IO error while reading/writing file
5998 */
5999 24573 int MYSQL_BIN_LOG::remove_logs_from_index(LOG_INFO *log_info,
6000 bool need_update_threads) {
6001
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24573 times.
24573 if (open_crash_safe_index_file()) {
6002 LogErr(ERROR_LEVEL, ER_BINLOG_CANT_OPEN_TMP_INDEX,
6003 "MYSQL_BIN_LOG::remove_logs_from_index");
6004 goto err;
6005 }
6006
6007
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24573 times.
24573 if (copy_file(&index_file, &crash_safe_index_file,
6008 log_info->index_file_start_offset)) {
6009 LogErr(ERROR_LEVEL, ER_BINLOG_CANT_COPY_INDEX_TO_TMP,
6010 "MYSQL_BIN_LOG::remove_logs_from_index");
6011 goto err;
6012 }
6013
6014
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24573 times.
24573 if (close_crash_safe_index_file()) {
6015 LogErr(ERROR_LEVEL, ER_BINLOG_CANT_CLOSE_TMP_INDEX,
6016 "MYSQL_BIN_LOG::remove_logs_from_index");
6017 goto err;
6018 }
6019
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 24570 times.
24573 DBUG_EXECUTE_IF("fault_injection_copy_part_file", DBUG_SUICIDE(););
6020
6021
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 24561 times.
24570 if (move_crash_safe_index_file_to_index_file(
6022 false /*need_lock_index=false*/)) {
6023
7/14
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
3 LogErr(ERROR_LEVEL, ER_BINLOG_CANT_MOVE_TMP_TO_INDEX,
6024 "MYSQL_BIN_LOG::remove_logs_from_index");
6025 3 goto err;
6026 }
6027
6028 // now update offsets in index file for running threads
6029
2/2
✓ Branch 0 taken 210 times.
✓ Branch 1 taken 24351 times.
24561 if (need_update_threads)
6030 210 adjust_linfo_offsets(log_info->index_file_start_offset);
6031 24561 return 0;
6032
6033 3 err:
6034 3 return LOG_INFO_IO;
6035 }
6036
6037 /**
6038 Remove all logs before the given log from disk and from the index file.
6039
6040 @param to_log Delete all log file name before this file.
6041 @param included If true, to_log is deleted too.
6042 @param need_lock_index Set to true, if the lock_index of the binary log
6043 shall be acquired, false if the called is already the owner of the lock_index.
6044 @param need_update_threads If we want to update the log coordinates of
6045 all threads. False for relay logs, true otherwise.
6046 @param decrease_log_space If not null, decrement this variable of
6047 the amount of log space freed
6048 @param auto_purge True if this is an automatic purge.
6049
6050 @note
6051 If any of the logs before the deleted one is in use,
6052 only purge logs up to this one.
6053
6054 @retval 0 ok
6055 @retval LOG_INFO_EOF to_log not found
6056 @retval LOG_INFO_EMFILE too many files opened
6057 @retval LOG_INFO_FATAL if any other than ENOENT error from
6058 mysql_file_stat() or mysql_file_delete()
6059 */
6060
6061 24578 int MYSQL_BIN_LOG::purge_logs(const char *to_log, bool included,
6062 bool need_lock_index, bool need_update_threads,
6063 ulonglong *decrease_log_space, bool auto_purge) {
6064 24578 int error = 0, no_of_log_files_to_purge = 0, no_of_log_files_purged = 0;
6065 24578 int no_of_threads_locking_log = 0;
6066 24578 bool exit_loop = false;
6067 24578 LOG_INFO log_info;
6068
1/2
✓ Branch 0 taken 24578 times.
✗ Branch 1 not taken.
24578 THD *thd = current_thd;
6069
1/2
✓ Branch 0 taken 24578 times.
✗ Branch 1 not taken.
24578 DBUG_TRACE;
6070
3/8
✓ Branch 0 taken 24578 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24578 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 24578 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
24578 DBUG_PRINT("info", ("to_log= %s", to_log));
6071
6072
2/2
✓ Branch 0 taken 138 times.
✓ Branch 1 taken 24440 times.
24578 if (need_lock_index)
6073
1/2
✓ Branch 0 taken 138 times.
✗ Branch 1 not taken.
138 mysql_mutex_lock(&LOCK_index);
6074 else
6075 24440 mysql_mutex_assert_owner(&LOCK_index);
6076 24578 if ((error =
6077
3/4
✓ Branch 0 taken 24578 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 24576 times.
24578 find_log_pos(&log_info, to_log, false /*need_lock_index=false*/))) {
6078
8/16
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 2 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 2 times.
✗ Branch 15 not taken.
2 LogErr(ERROR_LEVEL, ER_BINLOG_PURGE_LOGS_CALLED_WITH_FILE_NOT_IN_INDEX,
6079 to_log);
6080 2 goto err;
6081 }
6082
6083 24576 no_of_log_files_to_purge = log_info.entry_index;
6084
6085
2/4
✓ Branch 0 taken 24576 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 24576 times.
24576 if ((error = open_purge_index_file(true))) {
6086 LogErr(ERROR_LEVEL, ER_BINLOG_PURGE_LOGS_CANT_SYNC_INDEX_FILE);
6087 goto err;
6088 }
6089
6090 /*
6091 File name exists in index file; delete until we find this file
6092 or a file that is used.
6093 */
6094
2/4
✓ Branch 0 taken 24576 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 24576 times.
24576 if ((error = find_log_pos(&log_info, NullS, false /*need_lock_index=false*/)))
6095 goto err;
6096
6097
5/6
✓ Branch 0 taken 39752 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24576 times.
✓ Branch 3 taken 15176 times.
✓ Branch 4 taken 15266 times.
✓ Branch 5 taken 24486 times.
64328 while ((compare_log_name(to_log, log_info.log_file_name) ||
6098
2/2
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 24486 times.
24576 (exit_loop = included))) {
6099
2/4
✓ Branch 0 taken 15266 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 15266 times.
15266 if (is_active(log_info.log_file_name)) {
6100 if (!auto_purge)
6101 push_warning_printf(
6102 thd, Sql_condition::SL_WARNING, ER_WARN_PURGE_LOG_IS_ACTIVE,
6103 ER_THD(thd, ER_WARN_PURGE_LOG_IS_ACTIVE), log_info.log_file_name);
6104 break;
6105 }
6106
6107
2/4
✓ Branch 0 taken 15266 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 15266 times.
15266 if ((no_of_threads_locking_log = log_in_use(log_info.log_file_name))) {
6108 if (!auto_purge)
6109 push_warning_printf(thd, Sql_condition::SL_WARNING,
6110 ER_WARN_PURGE_LOG_IN_USE,
6111 ER_THD(thd, ER_WARN_PURGE_LOG_IN_USE),
6112 log_info.log_file_name, no_of_threads_locking_log,
6113 no_of_log_files_purged, no_of_log_files_to_purge);
6114 break;
6115 }
6116 15266 no_of_log_files_purged++;
6117
6118
2/4
✓ Branch 0 taken 15266 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 15266 times.
15266 if ((error = register_purge_index_entry(log_info.log_file_name))) {
6119 LogErr(ERROR_LEVEL, ER_BINLOG_PURGE_LOGS_CANT_COPY_TO_REGISTER_FILE,
6120 log_info.log_file_name);
6121 goto err;
6122 }
6123
6124
6/8
✓ Branch 0 taken 15266 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15266 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 90 times.
✓ Branch 5 taken 15176 times.
✓ Branch 6 taken 90 times.
✓ Branch 7 taken 15176 times.
15266 if (find_next_log(&log_info, false /*need_lock_index=false*/) || exit_loop)
6125 90 break;
6126 }
6127
6128
4/6
✓ Branch 0 taken 24576 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 24573 times.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
24576 DBUG_EXECUTE_IF("crash_purge_before_update_index", DBUG_SUICIDE(););
6129
6130
2/4
✓ Branch 0 taken 24573 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 24573 times.
24573 if ((error = sync_purge_index_file())) {
6131 LogErr(ERROR_LEVEL, ER_BINLOG_PURGE_LOGS_CANT_FLUSH_REGISTER_FILE);
6132 goto err;
6133 }
6134
6135 /* We know how many files to delete. Update index file. */
6136
3/4
✓ Branch 0 taken 24564 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 24561 times.
24573 if ((error = remove_logs_from_index(&log_info, need_update_threads))) {
6137
8/16
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 3 times.
✗ Branch 15 not taken.
3 LogErr(ERROR_LEVEL, ER_BINLOG_PURGE_LOGS_CANT_UPDATE_INDEX_FILE);
6138 3 goto err;
6139 }
6140
6141 // Update gtid_state->lost_gtids
6142
2/2
✓ Branch 0 taken 210 times.
✓ Branch 1 taken 24351 times.
24561 if (!is_relay_log) {
6143
1/2
✓ Branch 0 taken 210 times.
✗ Branch 1 not taken.
210 global_sid_lock->wrlock();
6144
1/2
✓ Branch 0 taken 210 times.
✗ Branch 1 not taken.
210 error = init_gtid_sets(
6145 210 nullptr, const_cast<Gtid_set *>(gtid_state->get_lost_gtids()),
6146 opt_source_verify_checksum, false /*false=don't need lock*/,
6147 nullptr /*trx_parser*/, nullptr /*partial_trx*/);
6148
1/2
✓ Branch 0 taken 210 times.
✗ Branch 1 not taken.
210 global_sid_lock->unlock();
6149
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 210 times.
210 if (error) goto err;
6150 }
6151
6152
4/6
✓ Branch 0 taken 24561 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 24558 times.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
24561 DBUG_EXECUTE_IF("crash_purge_critical_after_update_index", DBUG_SUICIDE(););
6153
6154 24558 err:
6155
6156 24563 int error_index = 0, close_error_index = 0;
6157 /* Read each entry from purge_index_file and delete the file. */
6158
6/8
✓ Branch 0 taken 24558 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 24558 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 24558 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✓ Branch 7 taken 24560 times.
49121 if (!error && is_inited_purge_index_file() &&
6159
3/4
✓ Branch 0 taken 24558 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 24555 times.
24558 (error_index = purge_index_entry(thd, decrease_log_space,
6160 false /*need_lock_index=false*/)))
6161
8/16
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 3 times.
✗ Branch 15 not taken.
3 LogErr(ERROR_LEVEL, ER_BINLOG_PURGE_LOGS_FAILED_TO_PURGE_LOG);
6162
6163
1/2
✓ Branch 0 taken 24563 times.
✗ Branch 1 not taken.
24563 close_error_index = close_purge_index_file();
6164
6165
4/6
✓ Branch 0 taken 24563 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 24560 times.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
24563 DBUG_EXECUTE_IF("crash_purge_non_critical_after_update_index",
6166 DBUG_SUICIDE(););
6167
6168
1/2
✓ Branch 0 taken 24560 times.
✗ Branch 1 not taken.
24560 count_binlog_space(false);
6169
3/4
✓ Branch 0 taken 120 times.
✓ Branch 1 taken 24440 times.
✓ Branch 2 taken 120 times.
✗ Branch 3 not taken.
24560 if (need_lock_index) mysql_mutex_unlock(&LOCK_index);
6170
6171 /*
6172 Error codes from purge logs take precedence.
6173 Then error codes from purging the index entry.
6174 Finally, error codes from closing the purge index file.
6175 */
6176
4/4
✓ Branch 0 taken 24555 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 24552 times.
24560 error = error ? error : (error_index ? error_index : close_error_index);
6177
6178 24560 return error;
6179 24560 }
6180
6181 84646 int MYSQL_BIN_LOG::set_purge_index_file_name(const char *base_file_name) {
6182 84646 int error = 0;
6183
1/2
✓ Branch 0 taken 84647 times.
✗ Branch 1 not taken.
84646 DBUG_TRACE;
6184 169294 if (fn_format(
6185
1/2
✓ Branch 0 taken 84647 times.
✗ Branch 1 not taken.
84647 purge_index_file_name, base_file_name, mysql_data_home, ".~rec~",
6186
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 84647 times.
84647 MYF(MY_UNPACK_FILENAME | MY_SAFE_PATH | MY_REPLACE_EXT)) == nullptr) {
6187 error = 1;
6188 LogErr(ERROR_LEVEL, ER_BINLOG_FAILED_TO_SET_PURGE_INDEX_FILE_NAME);
6189 }
6190 84647 return error;
6191 84647 }
6192
6193 193665 int MYSQL_BIN_LOG::open_purge_index_file(bool destroy) {
6194 193665 int error = 0;
6195 193665 File file = -1;
6196
6197
1/2
✓ Branch 0 taken 193665 times.
✗ Branch 1 not taken.
193665 DBUG_TRACE;
6198
6199
3/4
✓ Branch 0 taken 109018 times.
✓ Branch 1 taken 84647 times.
✓ Branch 2 taken 109018 times.
✗ Branch 3 not taken.
193665 if (destroy) close_purge_index_file();
6200
6201
1/2
✓ Branch 0 taken 193665 times.
✗ Branch 1 not taken.
193665 if (!my_b_inited(&purge_index_file)) {
6202 193665 myf flags = MY_WME | MY_NABP | MY_WAIT_IF_FULL;
6203
2/2
✓ Branch 0 taken 131892 times.
✓ Branch 1 taken 61773 times.
193665 if (is_relay_log) flags = flags | MY_REPORT_WAITING_IF_FULL;
6204
6205
1/2
✓ Branch 0 taken 193665 times.
✗ Branch 1 not taken.
193665 if ((file = my_open(purge_index_file_name, O_RDWR | O_CREAT, MYF(MY_WME))) <
6206
2/4
✓ Branch 0 taken 193665 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 193665 times.
387330 0 ||
6207
4/6
✓ Branch 0 taken 109018 times.
✓ Branch 1 taken 84647 times.
✓ Branch 2 taken 193665 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 193665 times.
193665 init_io_cache(&purge_index_file, file, IO_SIZE,
6208 (destroy ? WRITE_CACHE : READ_CACHE), 0, false, flags)) {
6209 error = 1;
6210 LogErr(ERROR_LEVEL, ER_BINLOG_FAILED_TO_OPEN_REGISTER_FILE);
6211 }
6212 }
6213 193665 return error;
6214 193665 }
6215
6216 302648 int MYSQL_BIN_LOG::close_purge_index_file() {
6217 302648 int error = 0;
6218
6219
1/2
✓ Branch 0 taken 302648 times.
✗ Branch 1 not taken.
302648 DBUG_TRACE;
6220
6221
2/2
✓ Branch 0 taken 193629 times.
✓ Branch 1 taken 109019 times.
302648 if (my_b_inited(&purge_index_file)) {
6222
1/2
✓ Branch 0 taken 193629 times.
✗ Branch 1 not taken.
193629 end_io_cache(&purge_index_file);
6223
1/2
✓ Branch 0 taken 193629 times.
✗ Branch 1 not taken.
193629 error = my_close(purge_index_file.file, MYF(0));
6224 }
6225
1/2
✓ Branch 0 taken 302648 times.
✗ Branch 1 not taken.
302648 my_delete(purge_index_file_name, MYF(0));
6226 302648 new (&purge_index_file) IO_CACHE();
6227
6228 302648 return error;
6229 302648 }
6230
6231 24569 bool MYSQL_BIN_LOG::is_inited_purge_index_file() {
6232
1/2
✓ Branch 0 taken 24569 times.
✗ Branch 1 not taken.
24569 DBUG_TRACE;
6233 49138 return my_b_inited(&purge_index_file);
6234 24569 }
6235
6236 109015 int MYSQL_BIN_LOG::sync_purge_index_file() {
6237 109015 int error = 0;
6238
1/2
✓ Branch 0 taken 109015 times.
✗ Branch 1 not taken.
109015 DBUG_TRACE;
6239
6240
5/6
✓ Branch 0 taken 109015 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 109014 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 109013 times.
218028 if ((error = flush_io_cache(&purge_index_file)) ||
6241
2/4
✓ Branch 0 taken 109013 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 109013 times.
109014 (error = my_sync(purge_index_file.file, MYF(MY_WME))))
6242 1 return error;
6243
6244 109013 return error;
6245 109014 }
6246
6247 99708 int MYSQL_BIN_LOG::register_purge_index_entry(const char *entry) {
6248 99708 int error = 0;
6249
1/2
✓ Branch 0 taken 99708 times.
✗ Branch 1 not taken.
99708 DBUG_TRACE;
6250
6251
1/2
✓ Branch 0 taken 99708 times.
✗ Branch 1 not taken.
99708 if ((error = my_b_write(&purge_index_file, (const uchar *)entry,
6252
2/4
✓ Branch 0 taken 99708 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 99708 times.
199416 strlen(entry))) ||
6253
2/4
✓ Branch 0 taken 99708 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 99708 times.
99708 (error = my_b_write(&purge_index_file, (const uchar *)"\n", 1)))
6254 return error;
6255
6256 99708 return error;
6257 99708 }
6258
6259 84442 int MYSQL_BIN_LOG::register_create_index_entry(const char *entry) {
6260
1/2
✓ Branch 0 taken 84442 times.
✗ Branch 1 not taken.
84442 DBUG_TRACE;
6261
1/2
✓ Branch 0 taken 84442 times.
✗ Branch 1 not taken.
168884 return register_purge_index_entry(entry);
6262 84442 }
6263
6264 109216 int MYSQL_BIN_LOG::purge_index_entry(THD *thd, ulonglong *decrease_log_space,
6265 bool need_lock_index) {
6266 MY_STAT s;
6267 109216 int error = 0;
6268 109216 LOG_INFO log_info;
6269 109216 LOG_INFO check_log_info;
6270
6271
1/2
✓ Branch 0 taken 109216 times.
✗ Branch 1 not taken.
109216 DBUG_TRACE;
6272
6273
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 109216 times.
109216 assert(my_b_inited(&purge_index_file));
6274
6275 109216 if ((error =
6276
2/4
✓ Branch 0 taken 109216 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 109216 times.
109216 reinit_io_cache(&purge_index_file, READ_CACHE, 0, false, false))) {
6277 LogErr(ERROR_LEVEL, ER_BINLOG_FAILED_TO_REINIT_REGISTER_FILE);
6278 goto err;
6279 }
6280
6281 for (;;) {
6282 size_t length;
6283
6284
1/2
✓ Branch 0 taken 124505 times.
✗ Branch 1 not taken.
124505 if ((length = my_b_gets(&purge_index_file, log_info.log_file_name,
6285
2/2
✓ Branch 0 taken 109213 times.
✓ Branch 1 taken 15292 times.
124505 FN_REFLEN)) <= 1) {
6286
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 109213 times.
109213 if (purge_index_file.error) {
6287 error = purge_index_file.error;
6288 LogErr(ERROR_LEVEL, ER_BINLOG_FAILED_TO_READ_REGISTER_FILE, error);
6289 goto err;
6290 }
6291
6292 /* Reached EOF */
6293 109213 break;
6294 }
6295
6296 /* Get rid of the trailing '\n' */
6297 15292 log_info.log_file_name[length - 1] = 0;
6298
6299
3/4
✓ Branch 0 taken 15292 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 15277 times.
15292 if (!mysql_file_stat(m_key_file_log, log_info.log_file_name, &s, MYF(0))) {
6300
2/4
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
15 if (my_errno() == ENOENT) {
6301 /*
6302 It's not fatal if we can't stat a log file that does not exist;
6303 If we could not stat, we won't delete.
6304 */
6305
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 9 times.
15 if (thd) {
6306
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
6 push_warning_printf(
6307 thd, Sql_condition::SL_WARNING, ER_LOG_PURGE_NO_FILE,
6308 ER_THD(thd, ER_LOG_PURGE_NO_FILE), log_info.log_file_name);
6309 }
6310
8/16
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 15 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 15 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 15 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 15 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 15 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 15 times.
✗ Branch 15 not taken.
15 LogErr(INFORMATION_LEVEL, ER_CANT_STAT_FILE, log_info.log_file_name);
6311
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 set_my_errno(0);
6312 } else {
6313 /*
6314 Other than ENOENT are fatal
6315 */
6316 if (thd) {
6317 push_warning_printf(thd, Sql_condition::SL_WARNING,
6318 ER_BINLOG_PURGE_FATAL_ERR,
6319 "a problem with getting info on being purged %s; "
6320 "consider examining correspondence "
6321 "of your binlog index file "
6322 "to the actual binlog files",
6323 log_info.log_file_name);
6324 } else {
6325 LogErr(INFORMATION_LEVEL,
6326 ER_BINLOG_CANT_DELETE_LOG_FILE_DOES_INDEX_MATCH_FILES,
6327 log_info.log_file_name);
6328 }
6329 error = LOG_INFO_FATAL;
6330 goto err;
6331 }
6332 } else {
6333
3/4
✓ Branch 0 taken 15277 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15262 times.
✓ Branch 3 taken 15 times.
15277 if ((error = find_log_pos(&check_log_info, log_info.log_file_name,
6334 need_lock_index))) {
6335
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15262 times.
15262 if (error != LOG_INFO_EOF) {
6336 if (thd) {
6337 push_warning_printf(thd, Sql_condition::SL_WARNING,
6338 ER_BINLOG_PURGE_FATAL_ERR,
6339 "a problem with deleting %s and "
6340 "reading the binlog index file",
6341 log_info.log_file_name);
6342 } else {
6343 LogErr(INFORMATION_LEVEL,
6344 ER_BINLOG_CANT_DELETE_FILE_AND_READ_BINLOG_INDEX,
6345 log_info.log_file_name);
6346 }
6347 goto err;
6348 }
6349
6350 15262 error = 0;
6351
1/2
✓ Branch 0 taken 15262 times.
✗ Branch 1 not taken.
15262 if (!need_lock_index) {
6352 /*
6353 This is to avoid triggering an error in NDB.
6354
6355 @todo: This is weird, what does NDB errors have to do with
6356 need_lock_index? Explain better or refactor /Sven
6357 */
6358
2/4
✓ Branch 0 taken 15262 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15262 times.
✗ Branch 3 not taken.
15262 ha_binlog_index_purge_file(current_thd, log_info.log_file_name);
6359 }
6360
6361
3/8
✓ Branch 0 taken 15262 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15262 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 15262 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
15262 DBUG_PRINT("info", ("purging %s", log_info.log_file_name));
6362
3/4
✓ Branch 0 taken 15262 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15259 times.
✓ Branch 3 taken 3 times.
15262 if (!mysql_file_delete(key_file_binlog, log_info.log_file_name,
6363 MYF(0))) {
6364
6/10
✓ Branch 0 taken 15259 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 15258 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
15259 DBUG_EXECUTE_IF("wait_in_purge_index_entry", {
6365 const char action[] =
6366 "now SIGNAL in_purge_index_entry WAIT_FOR go_ahead_sql";
6367 assert(!debug_sync_set_action(thd, STRING_WITH_LEN(action)));
6368 DBUG_SET("-d,wait_in_purge_index_entry");
6369 };);
6370
6371
2/2
✓ Branch 0 taken 14922 times.
✓ Branch 1 taken 337 times.
15259 if (decrease_log_space) *decrease_log_space -= s.st_size;
6372 } else {
6373
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
3 if (my_errno() == ENOENT) {
6374 if (thd) {
6375 push_warning_printf(
6376 thd, Sql_condition::SL_WARNING, ER_LOG_PURGE_NO_FILE,
6377 ER_THD(thd, ER_LOG_PURGE_NO_FILE), log_info.log_file_name);
6378 }
6379 LogErr(INFORMATION_LEVEL, ER_BINLOG_CANT_DELETE_FILE,
6380 log_info.log_file_name);
6381 set_my_errno(0);
6382 } else {
6383
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (thd) {
6384
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 push_warning_printf(thd, Sql_condition::SL_WARNING,
6385 ER_BINLOG_PURGE_FATAL_ERR,
6386 "a problem with deleting %s; "
6387 "consider examining correspondence "
6388 "of your binlog index file "
6389 "to the actual binlog files",
6390 log_info.log_file_name);
6391 } else {
6392 LogErr(INFORMATION_LEVEL,
6393 ER_BINLOG_CANT_DELETE_LOG_FILE_DOES_INDEX_MATCH_FILES,
6394 log_info.log_file_name);
6395 }
6396
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
3 if (my_errno() == EMFILE) {
6397 DBUG_PRINT("info", ("my_errno: %d, set ret = LOG_INFO_EMFILE",
6398 my_errno()));
6399 error = LOG_INFO_EMFILE;
6400 goto err;
6401 }
6402 3 error = LOG_INFO_FATAL;
6403 3 goto err;
6404 }
6405 }
6406 }
6407 }
6408 15289 }
6409
6410 109216 err:
6411 109216 return error;
6412 109216 }
6413
6414 /**
6415 Count a total size of binary logs (except the active one) to the variable
6416 binlog_space_total.
6417
6418 @param need_lock_index If true, this function acquires LOCK_index;
6419 otherwise the caller should already have acquired it.
6420
6421 @retval
6422 0 ok
6423 @retval
6424 LOG_INFO_FATAL if any other than ENOENT error from
6425 mysql_file_stat() or mysql_file_delete()
6426 LOG_INFO_EOF End of log-index-file found
6427 LOG_INFO_IO Got IO error while reading log-index-file
6428 */
6429
6430 54611 int MYSQL_BIN_LOG::count_binlog_space(bool need_lock_index) {
6431
1/2
✓ Branch 0 taken 54611 times.
✗ Branch 1 not taken.
54611 DBUG_ENTER("count_binlog_space");
6432
3/4
✓ Branch 0 taken 44571 times.
✓ Branch 1 taken 10040 times.
✓ Branch 2 taken 44571 times.
✗ Branch 3 not taken.
54611 if (is_relay_log) DBUG_RETURN(0);
6433
6434
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10040 times.
10040 if (need_lock_index)
6435 mysql_mutex_lock(&LOCK_index);
6436 else
6437 10040 mysql_mutex_assert_owner(&LOCK_index);
6438
6439 int error;
6440 10040 LOG_INFO log_info;
6441 10040 binlog_space_total = 0;
6442
3/4
✓ Branch 0 taken 10040 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 10031 times.
10040 if ((error = find_log_pos(&log_info, NullS, false /*need_lock_index=false*/)))
6443 9 goto done;
6444
6445 MY_STAT stat_area;
6446
3/4
✓ Branch 0 taken 10756 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 725 times.
✓ Branch 3 taken 10031 times.
10756 while (!(is_active(log_info.log_file_name))) {
6447
2/4
✓ Branch 0 taken 725 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 725 times.
725 if (!mysql_file_stat(m_key_file_log, log_info.log_file_name, &stat_area,
6448 MYF(0))) {
6449 if (my_errno() == ENOENT) {
6450 /*
6451 It's not fatal if we can't stat a log file that does not exist.
6452 */
6453 set_my_errno(0);
6454 } else {
6455 error = LOG_INFO_FATAL;
6456 goto done;
6457 }
6458 } else {
6459 725 binlog_space_total += stat_area.st_size;
6460 }
6461
2/4
✓ Branch 0 taken 725 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 725 times.
725 if (find_next_log(&log_info, false /*need_lock_index=false*/)) break;
6462 }
6463
6464 10031 error = 0;
6465
6466 10040 done:
6467
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 10040 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
10040 if (need_lock_index) mysql_mutex_unlock(&LOCK_index);
6468
1/2
✓ Branch 0 taken 10040 times.
✗ Branch 1 not taken.
10040 DBUG_RETURN(error);
6469 }
6470
6471 /**
6472 Purge old logs so that we have a total size lower than binlog_space_limit.
6473
6474 @param need_lock_index If true, this function acquires LOCK_index;
6475 otherwise the caller should already have acquired it.
6476
6477 @note
6478 If any of the logs before the deleted one is in use,
6479 only purge logs up to this one.
6480
6481 @retval
6482 0 ok
6483 @retval
6484 LOG_INFO_FATAL if any other than ENOENT error from
6485 mysql_file_stat() or mysql_file_delete()
6486 LOG_INFO_EOF End of log-index-file found
6487 LOG_INFO_IO Got IO error while reading log-index-file
6488 */
6489
6490 64 int MYSQL_BIN_LOG::purge_logs_by_size(bool need_lock_index) {
6491
1/2
✓ Branch 0 taken 64 times.
✗ Branch 1 not taken.
64 DBUG_ENTER("purge_logs_by_size");
6492
6493
2/6
✓ Branch 0 taken 64 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 64 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
64 if (is_relay_log || !binlog_space_limit) DBUG_RETURN(0);
6494
6495
1/2
✓ Branch 0 taken 64 times.
✗ Branch 1 not taken.
64 if (need_lock_index)
6496
1/2
✓ Branch 0 taken 64 times.
✗ Branch 1 not taken.
64 mysql_mutex_lock(&LOCK_index);
6497 else
6498 mysql_mutex_assert_owner(&LOCK_index);
6499
6500 64 int error = 0;
6501 64 LOG_INFO log_info;
6502 64 const auto binlog_pos = m_binlog_file->position();
6503
1/2
✓ Branch 0 taken 64 times.
✗ Branch 1 not taken.
64 count_binlog_space(false);
6504
6505
2/2
✓ Branch 0 taken 61 times.
✓ Branch 1 taken 3 times.
64 if (!binlog_space_total ||
6506
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 27 times.
61 binlog_space_total + binlog_pos <= binlog_space_limit)
6507 37 goto done;
6508
6509
2/4
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 27 times.
27 if ((error = find_log_pos(&log_info, NullS, false /*need_lock_index=false*/)))
6510 goto done;
6511
6512 MY_STAT stat_area;
6513 char to_log[FN_REFLEN];
6514 27 to_log[0] = 0;
6515
3/4
✓ Branch 0 taken 60 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 51 times.
✓ Branch 3 taken 9 times.
60 while (!is_active(log_info.log_file_name)) {
6516
2/4
✓ Branch 0 taken 51 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 51 times.
51 if (!mysql_file_stat(m_key_file_log, log_info.log_file_name, &stat_area,
6517 MYF(0))) {
6518 if (my_errno() == ENOENT) {
6519 /*
6520 It's not fatal if we can't stat a log file that does not exist.
6521 */
6522 set_my_errno(0);
6523 } else {
6524 /*
6525 Other than ENOENT are fatal
6526 */
6527 THD *thd = current_thd;
6528 if (thd) {
6529 push_warning_printf(thd, Sql_condition::SL_WARNING,
6530 ER_BINLOG_PURGE_FATAL_ERR,
6531 "a problem with getting info on being purged %s; "
6532 "consider examining correspondence "
6533 "of your binlog index file "
6534 "to the actual binlog files",
6535 log_info.log_file_name);
6536 } else {
6537 LogErr(INFORMATION_LEVEL, ER_CANT_STAT_FILE, log_info.log_file_name);
6538 }
6539 error = LOG_INFO_FATAL;
6540 goto done;
6541 }
6542 }
6543 /* check if a total size of binary logs is bigger than binlog_space_limit
6544 if yes check if it is in use, if not in use then add
6545 it in the list of binary log files to be purged.
6546 */
6547
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 18 times.
51 else if (binlog_space_total + binlog_pos > binlog_space_limit) {
6548
2/4
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 33 times.
33 if ((log_in_use(log_info.log_file_name))) break;
6549
3/8
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 33 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 33 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
33 DBUG_PRINT("info", ("purge_logs_by_size binlog_space_total=%llu "
6550 "binlog_pos=%llu sum=%llu\n",
6551 binlog_space_total, binlog_pos,
6552 binlog_space_total + binlog_pos));
6553
1/2
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
33 if (binlog_space_total >= (ulonglong)stat_area.st_size)
6554 33 binlog_space_total -= stat_area.st_size;
6555 else
6556 break;
6557
1/2
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
33 strmake(to_log, log_info.log_file_name,
6558 sizeof(log_info.log_file_name) - 1);
6559 } else
6560 18 break;
6561
2/4
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 33 times.
33 if (find_next_log(&log_info, false /*need_lock_index=false*/)) break;
6562 }
6563
6564
2/4
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 27 times.
✗ Branch 3 not taken.
27 error = (to_log[0] ? purge_logs(to_log, true, false /*need_lock_index=false*/,
6565 true /*need_update_threads=true*/, NULL, true)
6566 : 0);
6567
6568 64 done:
6569
2/4
✓ Branch 0 taken 64 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 64 times.
✗ Branch 3 not taken.
64 if (need_lock_index) mysql_mutex_unlock(&LOCK_index);
6570
1/2
✓ Branch 0 taken 64 times.
✗ Branch 1 not taken.
64 DBUG_RETURN(error);
6571 }
6572
6573 /**
6574 Remove all logs before the given file date from disk and from the
6575 index file.
6576
6577 @param purge_time Delete all log files before given date.
6578 @param auto_purge True if this is an automatic purge.
6579
6580 @note
6581 If any of the logs before the deleted one is in use,
6582 only purge logs up to this one.
6583
6584 @retval
6585 0 ok
6586 @retval
6587 LOG_INFO_PURGE_NO_ROTATE Binary file that can't be rotated
6588 LOG_INFO_FATAL if any other than ENOENT error from
6589 mysql_file_stat() or mysql_file_delete()
6590 */
6591
6592 19882 int MYSQL_BIN_LOG::purge_logs_before_date(time_t purge_time, bool auto_purge) {
6593 int error;
6594 19882 int no_of_threads_locking_log = 0, no_of_log_files_purged = 0;
6595 19882 bool log_is_active = false, log_is_in_use = false;
6596 char to_log[FN_REFLEN], copy_log_in_use[FN_REFLEN];
6597 19882 LOG_INFO log_info;
6598 MY_STAT stat_area;
6599
1/2
✓ Branch 0 taken 19882 times.
✗ Branch 1 not taken.
19882 THD *thd = current_thd;
6600
6601
1/2
✓ Branch 0 taken 19882 times.
✗ Branch 1 not taken.
19882 DBUG_TRACE;
6602
6603
1/2
✓ Branch 0 taken 19882 times.
✗ Branch 1 not taken.
19882 mysql_mutex_lock(&LOCK_index);
6604 19882 to_log[0] = 0;
6605
6606
2/4
✓ Branch 0 taken 19882 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 19882 times.
19882 if ((error = find_log_pos(&log_info, NullS, false /*need_lock_index=false*/)))
6607 goto err;
6608
6609
3/4
✓ Branch 0 taken 20011 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14862 times.
✓ Branch 3 taken 5149 times.
20011 while (!(log_is_active = is_active(log_info.log_file_name))) {
6610
3/4
✓ Branch 0 taken 14862 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 14859 times.
14862 if (!mysql_file_stat(m_key_file_log, log_info.log_file_name, &stat_area,
6611 MYF(0))) {
6612
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
3 if (my_errno() == ENOENT) {
6613 /*
6614 It's not fatal if we can't stat a log file that does not exist.
6615 */
6616
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 set_my_errno(0);
6617 } else {
6618 /*
6619 Other than ENOENT are fatal
6620 */
6621 if (thd) {
6622 push_warning_printf(thd, Sql_condition::SL_WARNING,
6623 ER_BINLOG_PURGE_FATAL_ERR,
6624 "a problem with getting info on being purged %s; "
6625 "consider examining correspondence "
6626 "of your binlog index file "
6627 "to the actual binlog files",
6628 log_info.log_file_name);
6629 } else {
6630 LogErr(INFORMATION_LEVEL, ER_BINLOG_FAILED_TO_DELETE_LOG_FILE,
6631 log_info.log_file_name);
6632 }
6633 error = LOG_INFO_FATAL;
6634 goto err;
6635 }
6636 }
6637 /* check if the binary log file is older than the purge_time
6638 if yes check if it is in use, if not in use then add
6639 it in the list of binary log files to be purged.
6640 */
6641
2/2
✓ Branch 0 taken 126 times.
✓ Branch 1 taken 14733 times.
14859 else if (stat_area.st_mtime < purge_time) {
6642
2/4
✓ Branch 0 taken 126 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 126 times.
126 if ((no_of_threads_locking_log = log_in_use(log_info.log_file_name))) {
6643 if (!auto_purge) {
6644 log_is_in_use = true;
6645 strcpy(copy_log_in_use, log_info.log_file_name);
6646 }
6647 break;
6648 }
6649
1/2
✓ Branch 0 taken 126 times.
✗ Branch 1 not taken.
126 strmake(to_log, log_info.log_file_name,
6650 sizeof(log_info.log_file_name) - 1);
6651 126 no_of_log_files_purged++;
6652 } else
6653 14733 break;
6654
2/4
✓ Branch 0 taken 129 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 129 times.
129 if (find_next_log(&log_info, false /*need_lock_index=false*/)) break;
6655 }
6656
6657
2/2
✓ Branch 0 taken 5149 times.
✓ Branch 1 taken 14733 times.
19882 if (log_is_active) {
6658
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 5132 times.
5149 if (!auto_purge)
6659
2/4
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
17 push_warning_printf(
6660 thd, Sql_condition::SL_WARNING, ER_WARN_PURGE_LOG_IS_ACTIVE,
6661 ER_THD(thd, ER_WARN_PURGE_LOG_IS_ACTIVE), log_info.log_file_name);
6662 }
6663
6664
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19882 times.
19882 if (log_is_in_use) {
6665 int no_of_log_files_to_purge = no_of_log_files_purged + 1;
6666 while (strcmp(log_file_name, log_info.log_file_name)) {
6667 if (mysql_file_stat(m_key_file_log, log_info.log_file_name, &stat_area,
6668 MYF(0))) {
6669 if (stat_area.st_mtime < purge_time)
6670 no_of_log_files_to_purge++;
6671 else
6672 break;
6673 }
6674 if (find_next_log(&log_info, false /*need_lock_index=false*/)) {
6675 no_of_log_files_to_purge++;
6676 break;
6677 }
6678 }
6679
6680 push_warning_printf(thd, Sql_condition::SL_WARNING,
6681 ER_WARN_PURGE_LOG_IN_USE,
6682 ER_THD(thd, ER_WARN_PURGE_LOG_IN_USE), copy_log_in_use,
6683 no_of_threads_locking_log, no_of_log_files_purged,
6684 no_of_log_files_to_purge);
6685 }
6686
6687
3/4
✓ Branch 0 taken 62 times.
✓ Branch 1 taken 19820 times.
✓ Branch 2 taken 62 times.
✗ Branch 3 not taken.
19882 error = (to_log[0] ? purge_logs(to_log, true, false /*need_lock_index=false*/,
6688 true /*need_update_threads=true*/,
6689 (ulonglong *)nullptr, auto_purge)
6690 : 0);
6691
6692 19882 err:
6693
1/2
✓ Branch 0 taken 19882 times.
✗ Branch 1 not taken.
19882 mysql_mutex_unlock(&LOCK_index);
6694 19882 return error;
6695 19882 }
6696
6697 /**
6698 Create a new log file name.
6699
6700 @param[out] buf Buffer allocated with at least FN_REFLEN bytes where
6701 new name is stored.
6702 @param log_ident Identity of the binary/relay log.
6703
6704 @note
6705 If file name will be longer then FN_REFLEN it will be truncated
6706 */
6707
6708 16766 void MYSQL_BIN_LOG::make_log_name(char *buf, const char *log_ident) {
6709 16766 size_t dir_len = dirname_length(log_file_name);
6710
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16766 times.
16766 if (dir_len >= FN_REFLEN) dir_len = FN_REFLEN - 1;
6711 16766 my_stpnmov(buf, log_file_name, dir_len);
6712 16766 strmake(buf + dir_len, log_ident, FN_REFLEN - dir_len - 1);
6713 16766 }
6714
6715 /**
6716 Check if we are writing/reading to the given log file.
6717 */
6718
6719 8205025 bool MYSQL_BIN_LOG::is_active(const char *log_file_name_arg) {
6720 8205025 return !compare_log_name(log_file_name, log_file_name_arg);
6721 }
6722
6723 5385682 void MYSQL_BIN_LOG::inc_prep_xids(THD *thd) {
6724
1/2
✓ Branch 0 taken 5385682 times.
✗ Branch 1 not taken.
5385682 DBUG_TRACE;
6725 #ifndef NDEBUG
6726 5385682 int result = ++m_atomic_prep_xids;
6727
5/8
✓ Branch 0 taken 5385682 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5385682 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 75 times.
✓ Branch 5 taken 5385607 times.
✓ Branch 6 taken 75 times.
✗ Branch 7 not taken.
5385682 DBUG_PRINT("debug", ("m_atomic_prep_xids: %d", result));
6728 #else
6729 m_atomic_prep_xids++;
6730 #endif
6731 5385682 thd->get_transaction()->m_flags.xid_written = true;
6732 5385682 }
6733
6734 5385542 void MYSQL_BIN_LOG::dec_prep_xids(THD *thd) {
6735
1/2
✓ Branch 0 taken 5385542 times.
✗ Branch 1 not taken.
5385542 DBUG_TRACE;
6736 5385542 int32 result = --m_atomic_prep_xids;
6737
5/8
✓ Branch 0 taken 5385542 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5385542 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 73 times.
✓ Branch 5 taken 5385469 times.
✓ Branch 6 taken 73 times.
✗ Branch 7 not taken.
5385542 DBUG_PRINT("debug", ("m_atomic_prep_xids: %d", result));
6738 5385542 thd->get_transaction()->m_flags.xid_written = false;
6739
2/2
✓ Branch 0 taken 5211159 times.
✓ Branch 1 taken 174383 times.
5385542 if (result == 0) {
6740
1/2
✓ Branch 0 taken 5211159 times.
✗ Branch 1 not taken.
5211159 mysql_mutex_lock(&LOCK_xids);
6741
1/2
✓ Branch 0 taken 5211159 times.
✗ Branch 1 not taken.
5211159 mysql_cond_signal(&m_prep_xids_cond);
6742
1/2
✓ Branch 0 taken 5211159 times.
✗ Branch 1 not taken.
5211159 mysql_mutex_unlock(&LOCK_xids);
6743 }
6744 5385542 }
6745
6746 /*
6747 Wrappers around new_file_impl to avoid using argument
6748 to control locking. The argument 1) less readable 2) breaks
6749 incapsulation 3) allows external access to the class without
6750 a lock (which is not possible with private new_file_without_locking
6751 method).
6752
6753 @retval
6754 nonzero - error
6755
6756 */
6757
6758 int MYSQL_BIN_LOG::new_file(
6759 Format_description_log_event *extra_description_event) {
6760 return new_file_impl(true /*need_lock_log=true*/, extra_description_event);
6761 }
6762
6763 /*
6764 @retval
6765 nonzero - error
6766 */
6767 34006 int MYSQL_BIN_LOG::new_file_without_locking(
6768 Format_description_log_event *extra_description_event) {
6769 34006 return new_file_impl(false /*need_lock_log=false*/, extra_description_event);
6770 }
6771
6772 /**
6773 Start writing to a new log file or reopen the old file.
6774
6775 @param need_lock_log If true, this function acquires LOCK_log;
6776 otherwise the caller should already have acquired it.
6777
6778 @param extra_description_event The master's FDE to be written by the I/O
6779 thread while creating a new relay log file. This should be NULL for
6780 binary log files.
6781
6782 @retval 0 success
6783 @retval nonzero - error
6784
6785 @note The new file name is stored last in the index file
6786 */
6787 34006 int MYSQL_BIN_LOG::new_file_impl(
6788 bool need_lock_log, Format_description_log_event *extra_description_event) {
6789 34006 int error = 0;
6790 34006 bool close_on_error = false;
6791 34006 char new_name[FN_REFLEN], *new_name_ptr = nullptr, *old_name, *file_to_open;
6792 34006 const size_t ERR_CLOSE_MSG_LEN = 1024;
6793 char close_on_error_msg[ERR_CLOSE_MSG_LEN];
6794 34006 memset(close_on_error_msg, 0, sizeof close_on_error_msg);
6795
6796
1/2
✓ Branch 0 taken 34006 times.
✗ Branch 1 not taken.
34006 DBUG_TRACE;
6797
2/2
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 33977 times.
34006 if (!is_open()) {
6798
3/8
✓ Branch 0 taken 29 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 29 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 29 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
29 DBUG_PRINT("info", ("log is closed"));
6799 29 return error;
6800 }
6801
6802
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33977 times.
33977 if (need_lock_log)
6803 mysql_mutex_lock(&LOCK_log);
6804 else
6805 33977 mysql_mutex_assert_owner(&LOCK_log);
6806
6/10
✓ Branch 0 taken 33977 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 33968 times.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 9 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 9 times.
✗ Branch 9 not taken.
33977 DBUG_EXECUTE_IF("semi_sync_3-way_deadlock",
6807 DEBUG_SYNC(current_thd, "before_rotate_binlog"););
6808
1/2
✓ Branch 0 taken 33977 times.
✗ Branch 1 not taken.
33977 mysql_mutex_lock(&LOCK_xids);
6809 /*
6810 We need to ensure that the number of prepared XIDs are 0.
6811
6812 If m_atomic_prep_xids is not zero:
6813 - We wait for storage engine commit, hence decrease m_atomic_prep_xids
6814 - We keep the LOCK_log to block new transactions from being
6815 written to the binary log.
6816 */
6817
2/2
✓ Branch 0 taken 1300 times.
✓ Branch 1 taken 33977 times.
35277 while (get_prep_xids() > 0) {
6818
1/2
✓ Branch 0 taken 1300 times.
✗ Branch 1 not taken.
1300 mysql_cond_wait(&m_prep_xids_cond, &LOCK_xids);
6819 }
6820
1/2
✓ Branch 0 taken 33977 times.
✗ Branch 1 not taken.
33977 mysql_mutex_unlock(&LOCK_xids);
6821
6822
1/2
✓ Branch 0 taken 33977 times.
✗ Branch 1 not taken.
33977 mysql_mutex_lock(&LOCK_index);
6823
6824 33977 mysql_mutex_assert_owner(&LOCK_log);
6825 33977 mysql_mutex_assert_owner(&LOCK_index);
6826
6827
3/6
✓ Branch 0 taken 33977 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 33977 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 33977 times.
67954 if (DBUG_EVALUATE_IF("expire_logs_always", 0, 1) &&
6828
2/4
✓ Branch 0 taken 33977 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 33977 times.
33977 (error = ha_flush_logs())) {
6829 goto end;
6830 }
6831
6832
2/2
✓ Branch 0 taken 9712 times.
✓ Branch 1 taken 24265 times.
33977 if (!is_relay_log) {
6833 /* Save set of GTIDs of the last binlog into table on binlog rotation */
6834
3/4
✓ Branch 0 taken 9712 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 9709 times.
9712 if ((error = gtid_state->save_gtids_of_last_binlog_into_table())) {
6835
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (error == ER_RPL_GTID_TABLE_CANNOT_OPEN) {
6836 3 close_on_error =
6837 3 m_binlog_file->get_real_file_size() >=
6838
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
6 static_cast<my_off_t>(max_size) ||
6839
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
3 DBUG_EVALUATE_IF("simulate_max_binlog_size", true, false);
6840
6841
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (!close_on_error) {
6842
8/16
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 3 times.
✗ Branch 15 not taken.
3 LogErr(ERROR_LEVEL, ER_BINLOG_UNABLE_TO_ROTATE_GTID_TABLE_READONLY,
6843 "Current binlog file was flushed to disk and will be kept in "
6844 "use.");
6845 } else {
6846 snprintf(close_on_error_msg, sizeof close_on_error_msg,
6847 ER_THD(current_thd, ER_RPL_GTID_TABLE_CANNOT_OPEN), "mysql",
6848 "gtid_executed");
6849
6850 if (binlog_error_action != ABORT_SERVER)
6851 LogErr(WARNING_LEVEL,
6852 ER_BINLOG_UNABLE_TO_ROTATE_GTID_TABLE_READONLY,
6853 "Binary logging going to be disabled.");
6854 }
6855
6856
2/6
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
3 DBUG_EXECUTE_IF("gtid_executed_readonly",
6857 { DBUG_SET("-d,gtid_executed_readonly"); });
6858
2/6
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
3 DBUG_EXECUTE_IF("simulate_max_binlog_size",
6859 { DBUG_SET("-d,simulate_max_binlog_size"); });
6860 } else {
6861 close_on_error = true;
6862 snprintf(close_on_error_msg, sizeof close_on_error_msg, "%s",
6863 ER_THD(current_thd, ER_OOM_SAVE_GTIDS));
6864 }
6865 3 goto end;
6866 }
6867 }
6868
6869 /*
6870 If user hasn't specified an extension, generate a new log name
6871 We have to do this here and not in open as we want to store the
6872 new file name in the current binary log file.
6873 */
6874 33974 new_name_ptr = new_name;
6875
3/4
✓ Branch 0 taken 33974 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 33959 times.
33974 if ((error = generate_new_name(new_name, name))) {
6876 // Use the old name if generation of new name fails.
6877 15 strcpy(new_name, name);
6878 15 close_on_error = true;
6879 45 snprintf(close_on_error_msg, sizeof close_on_error_msg,
6880
2/4
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
15 ER_THD(current_thd, ER_NO_UNIQUE_LOGFILE), name);
6881
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 if (strlen(close_on_error_msg)) {
6882 15 close_on_error_msg[strlen(close_on_error_msg) - 1] = '\0';
6883 }
6884 15 goto end;
6885 }
6886
6887 /*
6888 Make sure that the log_file is initialized before writing
6889 Rotate_log_event into it.
6890 */
6891
2/2
✓ Branch 0 taken 33958 times.
✓ Branch 1 taken 1 times.
33959 if (m_binlog_file->is_open()) {
6892 /*
6893 We log the whole file name for log file as the user may decide
6894 to change base names at some point.
6895 */
6896
1/2
✓ Branch 0 taken 33958 times.
✗ Branch 1 not taken.
33958 Rotate_log_event r(new_name + dirname_length(new_name), 0, LOG_EVENT_OFFSET,
6897
3/4
✓ Branch 0 taken 24264 times.
✓ Branch 1 taken 9694 times.
✓ Branch 2 taken 33958 times.
✗ Branch 3 not taken.
67916 is_relay_log ? Rotate_log_event::RELAY_LOG : 0);
6898
6899
3/4
✓ Branch 0 taken 33958 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 33953 times.
33958 if (DBUG_EVALUATE_IF("fault_injection_new_file_rotate_event", (error = 1),
6900
4/4
✓ Branch 0 taken 33953 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 33952 times.
67910 false) ||
6901
2/4
✓ Branch 0 taken 33952 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 33952 times.
33953 (error = write_event_to_binlog(&r))) {
6902 char errbuf[MYSYS_STRERROR_SIZE];
6903
2/4
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
5 DBUG_EXECUTE_IF("fault_injection_new_file_rotate_event", errno = 2;);
6904 5 close_on_error = true;
6905 20 snprintf(close_on_error_msg, sizeof close_on_error_msg,
6906
2/4
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
5 ER_THD(current_thd, ER_ERROR_ON_WRITE), name, errno,
6907
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 my_strerror(errbuf, sizeof(errbuf), errno));
6908
2/4
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
5 my_printf_error(ER_ERROR_ON_WRITE, ER_THD(current_thd, ER_ERROR_ON_WRITE),
6909
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 MYF(ME_FATALERROR), name, errno,
6910
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 my_strerror(errbuf, sizeof(errbuf), errno));
6911 5 goto end;
6912 }
6913
6914
2/4
✓ Branch 0 taken 33952 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 33952 times.
33952 if ((error = m_binlog_file->flush())) {
6915 close_on_error = true;
6916 snprintf(close_on_error_msg, sizeof close_on_error_msg, "%s",
6917 "Either disk is full or file system is read only");
6918 goto end;
6919 }
6920
2/2
✓ Branch 0 taken 33952 times.
✓ Branch 1 taken 5 times.
33957 }
6921
6922
3/6
✓ Branch 0 taken 33954 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 33953 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 33954 times.
✗ Branch 5 not taken.
33953 DEBUG_SYNC(current_thd, "after_rotate_event_appended");
6923
6924 33953 old_name = name;
6925 33953 name = nullptr; // Don't free name
6926
1/2
✓ Branch 0 taken 33954 times.
✗ Branch 1 not taken.
33953 close(LOG_CLOSE_TO_BE_OPENED | LOG_CLOSE_INDEX, false /*need_lock_log=false*/,
6927 false /*need_lock_index=false*/);
6928
6929
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 33938 times.
33954 if (checksum_alg_reset != binary_log::BINLOG_CHECKSUM_ALG_UNDEF) {
6930
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 assert(!is_relay_log);
6931
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 assert(binlog_checksum_options != checksum_alg_reset);
6932 16 binlog_checksum_options = checksum_alg_reset;
6933 }
6934 /*
6935 Note that at this point, atomic_log_state != LOG_CLOSED
6936 (important for is_open()).
6937 */
6938
6939
3/6
✓ Branch 0 taken 33954 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 33954 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 33954 times.
✗ Branch 5 not taken.
33954 DEBUG_SYNC(current_thd, "binlog_rotate_between_close_and_open");
6940 /*
6941 new_file() is only used for rotation (in FLUSH LOGS or because size >
6942 max_binlog_size or max_relay_log_size).
6943 If this is a binary log, the Format_description_log_event at the beginning
6944 of the new file should have created=0 (to distinguish with the
6945 Format_description_log_event written at server startup, which should
6946 trigger temp tables deletion on slaves.
6947 */
6948
6949 /* reopen index binlog file, BUG#34582 */
6950 33954 file_to_open = index_file_name;
6951
1/2
✓ Branch 0 taken 33954 times.
✗ Branch 1 not taken.
33954 error = open_index_file(index_file_name, nullptr,
6952 false /*need_lock_index=false*/);
6953
2/2
✓ Branch 0 taken 33951 times.
✓ Branch 1 taken 3 times.
33954 if (!error) {
6954 /* reopen the binary log file. */
6955 33951 file_to_open = new_name_ptr;
6956
1/2
✓ Branch 0 taken 33936 times.
✗ Branch 1 not taken.
33951 error = open_binlog(old_name, new_name_ptr, max_size,
6957 true /*null_created_arg=true*/,
6958 false /*need_lock_index=false*/,
6959 true /*need_sid_lock=true*/, extra_description_event);
6960 }
6961
6962 /* handle reopening errors */
6963
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 33919 times.
33939 if (error) {
6964 char errbuf[MYSYS_STRERROR_SIZE];
6965
4/8
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 20 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 20 times.
✗ Branch 7 not taken.
20 my_printf_error(ER_CANT_OPEN_FILE, ER_THD(current_thd, ER_CANT_OPEN_FILE),
6966 MYF(ME_FATALERROR), file_to_open, error,
6967 my_strerror(errbuf, sizeof(errbuf), error));
6968 20 close_on_error = true;
6969
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
40 snprintf(close_on_error_msg, sizeof close_on_error_msg,
6970
2/4
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 20 times.
✗ Branch 3 not taken.
20 ER_THD(current_thd, ER_CANT_OPEN_FILE), file_to_open, error,
6971 my_strerror(errbuf, sizeof(errbuf), error));
6972 }
6973
1/2
✓ Branch 0 taken 33939 times.
✗ Branch 1 not taken.
33939 my_free(old_name);
6974
6975 33962 end:
6976
6977
4/4
✓ Branch 0 taken 43 times.
✓ Branch 1 taken 33919 times.
✓ Branch 2 taken 40 times.
✓ Branch 3 taken 3 times.
33962 if (error && close_on_error /* rotate, flush or reopen failed */) {
6978 /*
6979 Close whatever was left opened.
6980
6981 We are keeping the behavior as it exists today, ie,
6982 we disable logging and move on (see: BUG#51014).
6983
6984 TODO: as part of WL#1790 consider other approaches:
6985 - kill mysql (safety);
6986 - try multiple locations for opening a log file;
6987 - switch server to protected/readonly mode
6988 - ...
6989 */
6990
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 40 times.
40 if (binlog_error_action == ABORT_SERVER) {
6991 char abort_msg[ERR_CLOSE_MSG_LEN + 48];
6992 memset(abort_msg, 0, sizeof abort_msg);
6993 snprintf(abort_msg, sizeof abort_msg,
6994 "%s, while rotating the binlog. "
6995 "Aborting the server",
6996 close_on_error_msg);
6997 exec_binlog_error_action_abort(abort_msg);
6998 } else
6999
9/18
✓ Branch 0 taken 40 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 40 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 40 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 40 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 40 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 40 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 40 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 40 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 40 times.
✗ Branch 17 not taken.
40 LogErr(ERROR_LEVEL, ER_BINLOG_CANT_OPEN_FOR_LOGGING,
7000 new_name_ptr != nullptr ? new_name_ptr : "new file", errno);
7001
7002
1/2
✓ Branch 0 taken 40 times.
✗ Branch 1 not taken.
40 close(LOG_CLOSE_INDEX, false /*need_lock_log=false*/,
7003 false /*need_lock_index=false*/);
7004 }
7005
7006
1/2
✓ Branch 0 taken 33962 times.
✗ Branch 1 not taken.
33962 mysql_mutex_unlock(&LOCK_index);
7007
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 33962 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
33962 if (need_lock_log) mysql_mutex_unlock(&LOCK_log);
7008
7009
3/6
✓ Branch 0 taken 33962 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 33962 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 33962 times.
✗ Branch 5 not taken.
33962 DEBUG_SYNC(current_thd, "after_disable_binlog");
7010 33962 return error;
7011 33991 }
7012
7013 /**
7014 Called after an event has been written to the relay log by the IO
7015 thread. This flushes and possibly syncs the file (according to the
7016 sync options), rotates the file if it has grown over the limit, and
7017 finally calls signal_update().
7018
7019 @note The caller must hold LOCK_log before invoking this function.
7020
7021 @param mi Master_info for the IO thread.
7022
7023 @retval false success
7024 @retval true error
7025 */
7026 1767052 bool MYSQL_BIN_LOG::after_write_to_relay_log(Master_info *mi) {
7027
1/2
✓ Branch 0 taken 1767052 times.
✗ Branch 1 not taken.
1767052 DBUG_TRACE;
7028
3/8
✓ Branch 0 taken 1767052 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1767052 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1767052 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
1767052 DBUG_PRINT("info", ("max_size: %lu", max_size));
7029
7030 // Check pre-conditions
7031 1767052 mysql_mutex_assert_owner(&LOCK_log);
7032
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1767052 times.
1767052 assert(is_relay_log);
7033
7034 /*
7035 We allow the relay log rotation by relay log size
7036 only if the trx parser is not inside a transaction.
7037 */
7038 1767052 bool can_rotate = mi->transaction_parser.is_not_inside_transaction();
7039
7040 #ifndef NDEBUG
7041 1767052 if (m_binlog_file->get_real_file_size() >
7042
6/8
✓ Branch 0 taken 1767052 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1767052 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18624 times.
✓ Branch 5 taken 1748428 times.
✓ Branch 6 taken 18439 times.
✓ Branch 7 taken 1748613 times.
1785676 DBUG_EVALUATE_IF("rotate_replica_debug_group", 500, max_size) &&
7043
2/2
✓ Branch 0 taken 18439 times.
✓ Branch 1 taken 185 times.
18624 !can_rotate) {
7044
3/8
✓ Branch 0 taken 18439 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18439 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 18439 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
18439 DBUG_PRINT("info", ("Postponing the rotation by size waiting for "
7045 "the end of the current transaction."));
7046 }
7047 #endif
7048
7049 // Flush and sync
7050
1/2
✓ Branch 0 taken 1767052 times.
✗ Branch 1 not taken.
1767052 bool error = flush_and_sync(false);
7051
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 1767046 times.
1767052 if (error) {
7052
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 mi->report(ERROR_LEVEL, ER_SLAVE_RELAY_LOG_WRITE_FAILURE,
7053
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
6 ER_THD(current_thd, ER_SLAVE_RELAY_LOG_WRITE_FAILURE),
7054 "failed to flush event to relay log file");
7055
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 truncate_relaylog_file(mi, atomic_binlog_end_pos);
7056 } else {
7057
2/2
✓ Branch 0 taken 371360 times.
✓ Branch 1 taken 1395686 times.
1767046 if (can_rotate) {
7058
1/2
✓ Branch 0 taken 371360 times.
✗ Branch 1 not taken.
371360 mysql_mutex_lock(&mi->data_lock);
7059 /*
7060 If the last event of the transaction has been flushed, we can add
7061 the GTID (if it is not empty) to the logged set, or else it will
7062 not be available in the Previous GTIDs of the next relay log file
7063 if we are going to rotate the relay log.
7064 */
7065
1/2
✓ Branch 0 taken 371360 times.
✗ Branch 1 not taken.
371360 const Gtid *last_gtid_queued = mi->get_queueing_trx_gtid();
7066
2/2
✓ Branch 0 taken 58304 times.
✓ Branch 1 taken 313056 times.
371360 if (!last_gtid_queued->is_empty()) {
7067
1/2
✓ Branch 0 taken 58304 times.
✗ Branch 1 not taken.
58304 mi->rli->get_sid_lock()->rdlock();
7068
6/10
✓ Branch 0 taken 58304 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 58298 times.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 6 times.
58304 DBUG_SIGNAL_WAIT_FOR(current_thd, "updating_received_transaction_set",
7069 "reached_updating_received_transaction_set",
7070 "continue_updating_received_transaction_set");
7071 58304 mi->rli->add_logged_gtid(last_gtid_queued->sidno,
7072
1/2
✓ Branch 0 taken 58304 times.
✗ Branch 1 not taken.
58304 last_gtid_queued->gno);
7073
1/2
✓ Branch 0 taken 58304 times.
✗ Branch 1 not taken.
58304 mi->rli->get_sid_lock()->unlock();
7074 }
7075
7076
3/4
✓ Branch 0 taken 371360 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 327375 times.
✓ Branch 3 taken 43985 times.
371360 if (mi->is_queueing_trx()) {
7077
1/2
✓ Branch 0 taken 327375 times.
✗ Branch 1 not taken.
327375 mi->finished_queueing();
7078
7079
1/2
✓ Branch 0 taken 327375 times.
✗ Branch 1 not taken.
327375 Trx_monitoring_info processing;
7080
1/2
✓ Branch 0 taken 327375 times.
✗ Branch 1 not taken.
327375 Trx_monitoring_info last;
7081
1/2
✓ Branch 0 taken 327375 times.
✗ Branch 1 not taken.
327375 mi->get_gtid_monitoring_info()->copy_info_to(&processing, &last);
7082
7083 // update the compression information
7084
1/2
✓ Branch 0 taken 327375 times.
✗ Branch 1 not taken.
327375 binlog::global_context.monitoring_context()
7085
1/2
✓ Branch 0 taken 327375 times.
✗ Branch 1 not taken.
327375 .transaction_compression()
7086 327375 .update(binlog::monitoring::log_type::RELAY, last.compression_type,
7087 327375 last.gtid, last.end_time, last.compressed_bytes,
7088
1/2
✓ Branch 0 taken 327375 times.
✗ Branch 1 not taken.
327375 last.uncompressed_bytes,
7089 327375 mi->rli->get_gtid_set()->get_sid_map());
7090 }
7091
1/2
✓ Branch 0 taken 371360 times.
✗ Branch 1 not taken.
371360 mysql_mutex_unlock(&mi->data_lock);
7092
7093 /*
7094 If relay log is too big, rotate. But only if not in the middle of a
7095 transaction when GTIDs are enabled.
7096
7097 Also rotate if a deferred flush request has been placed.
7098
7099 We now try to mimic the following master binlog behavior: "A transaction
7100 is written in one chunk to the binary log, so it is never split between
7101 several binary logs. Therefore, if you have big transactions, you might
7102 see binary log files larger than max_binlog_size."
7103 */
7104 371360 if (m_binlog_file->get_real_file_size() >
7105
6/8
✓ Branch 0 taken 371360 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 371360 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 371175 times.
✓ Branch 5 taken 185 times.
✓ Branch 6 taken 186 times.
✓ Branch 7 taken 371174 times.
742535 DBUG_EVALUATE_IF("rotate_replica_debug_group", 500, max_size) ||
7106
3/4
✓ Branch 0 taken 371175 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 371174 times.
371175 mi->is_rotate_requested()) {
7107
1/2
✓ Branch 0 taken 186 times.
✗ Branch 1 not taken.
186 error = new_file_without_locking(mi->get_mi_description_event());
7108
1/2
✓ Branch 0 taken 186 times.
✗ Branch 1 not taken.
186 mi->clear_rotate_requests();
7109 }
7110 }
7111 }
7112
7113
1/2
✓ Branch 0 taken 1767052 times.
✗ Branch 1 not taken.
1767052 lock_binlog_end_pos();
7114 1767052 mi->rli->ign_master_log_name_end[0] = 0;
7115
1/2
✓ Branch 0 taken 1767052 times.
✗ Branch 1 not taken.
1767052 update_binlog_end_pos(false /*need_lock*/);
7116
1/2
✓ Branch 0 taken 1767052 times.
✗ Branch 1 not taken.
1767052 harvest_bytes_written(mi->rli, true /*need_log_space_lock=true*/);
7117
1/2
✓ Branch 0 taken 1767052 times.
✗ Branch 1 not taken.
1767052 unlock_binlog_end_pos();
7118
7119 1767052 return error;
7120 1767052 }
7121
7122 12076 bool MYSQL_BIN_LOG::write_event(Log_event *ev, Master_info *mi) {
7123
1/2
✓ Branch 0 taken 12076 times.
✗ Branch 1 not taken.
12076 DBUG_TRACE;
7124
7125
3/4
✓ Branch 0 taken 12076 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 12075 times.
12076 DBUG_EXECUTE_IF("fail_to_write_ignored_event_to_relay_log", { return true; });
7126 // check preconditions
7127
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12075 times.
12075 assert(is_relay_log);
7128
7129 12075 mysql_mutex_assert_owner(&LOCK_log);
7130
7131 // write data
7132 12075 bool error = false;
7133
2/4
✓ Branch 0 taken 12075 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12075 times.
✗ Branch 3 not taken.
12075 if (!binary_event_serialize(ev, m_binlog_file)) {
7134 12075 bytes_written += ev->common_header->data_written;
7135
1/2
✓ Branch 0 taken 12075 times.
✗ Branch 1 not taken.
12075 error = after_write_to_relay_log(mi);
7136 } else {
7137 mi->report(ERROR_LEVEL, ER_SLAVE_RELAY_LOG_WRITE_FAILURE,
7138 ER_THD(current_thd, ER_SLAVE_RELAY_LOG_WRITE_FAILURE),
7139 "failed to write event to the relay log file");
7140 truncate_relaylog_file(mi, atomic_binlog_end_pos);
7141 error = true;
7142 }
7143
7144 12075 return error;
7145 12076 }
7146
7147 1754977 bool MYSQL_BIN_LOG::write_buffer(uchar *buf, uint len, Master_info *mi) {
7148
1/2
✓ Branch 0 taken 1754977 times.
✗ Branch 1 not taken.
1754977 DBUG_TRACE;
7149
7150 // check preconditions
7151
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1754977 times.
1754977 assert(is_relay_log);
7152 1754977 mysql_mutex_assert_owner(&LOCK_log);
7153
7154 // write data
7155 1754977 bool error = false;
7156
2/4
✓ Branch 0 taken 1754977 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1754977 times.
✗ Branch 3 not taken.
1754977 if (m_binlog_file->write(pointer_cast<const uchar *>(buf), len) == 0) {
7157 1754977 bytes_written += len;
7158
1/2
✓ Branch 0 taken 1754977 times.
✗ Branch 1 not taken.
1754977 error = after_write_to_relay_log(mi);
7159 } else {
7160 mi->report(ERROR_LEVEL, ER_SLAVE_RELAY_LOG_WRITE_FAILURE,
7161 ER_THD(current_thd, ER_SLAVE_RELAY_LOG_WRITE_FAILURE),
7162 "failed to write event to the relay log file");
7163 truncate_relaylog_file(mi, atomic_binlog_end_pos);
7164 error = true;
7165 }
7166
7167 1754977 return error;
7168 1754977 }
7169
7170 12601 bool MYSQL_BIN_LOG::flush() {
7171
3/4
✓ Branch 0 taken 12598 times.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 12598 times.
12601 return m_binlog_file->is_open() && m_binlog_file->flush();
7172 }
7173
7174 1775631 bool MYSQL_BIN_LOG::flush_and_sync(const bool force) {
7175 1775631 mysql_mutex_assert_owner(&LOCK_log);
7176
7177
3/4
✓ Branch 0 taken 1775631 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 1775625 times.
1775631 if (m_binlog_file->flush()) return true;
7178
7179
1/2
✓ Branch 0 taken 1775625 times.
✗ Branch 1 not taken.
1775625 std::pair<bool, bool> result = sync_binlog_file(force);
7180
7181 1775625 return result.first;
7182 }
7183
7184 44049 void MYSQL_BIN_LOG::start_union_events(THD *thd, query_id_t query_id_param) {
7185
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 44049 times.
44049 assert(!thd->binlog_evt_union.do_union);
7186 44049 thd->binlog_evt_union.do_union = true;
7187 44049 thd->binlog_evt_union.unioned_events = false;
7188 44049 thd->binlog_evt_union.unioned_events_trans = false;
7189 44049 thd->binlog_evt_union.first_query_id = query_id_param;
7190 44049 }
7191
7192 44049 void MYSQL_BIN_LOG::stop_union_events(THD *thd) {
7193
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 44049 times.
44049 assert(thd->binlog_evt_union.do_union);
7194 44049 thd->binlog_evt_union.do_union = false;
7195 44049 }
7196
7197 169205 bool MYSQL_BIN_LOG::is_query_in_union(THD *thd, query_id_t query_id_param) {
7198
2/2
✓ Branch 0 taken 122 times.
✓ Branch 1 taken 169083 times.
169327 return (thd->binlog_evt_union.do_union &&
7199
2/2
✓ Branch 0 taken 50 times.
✓ Branch 1 taken 72 times.
169327 query_id_param >= thd->binlog_evt_union.first_query_id);
7200 }
7201
7202 /*
7203 Updates thd's position-of-next-event variables
7204 after a *real* write a file.
7205 */
7206 5927057 void MYSQL_BIN_LOG::update_thd_next_event_pos(THD *thd) {
7207
1/2
✓ Branch 0 taken 5927057 times.
✗ Branch 1 not taken.
5927057 if (likely(thd != nullptr)) {
7208 5927057 thd->set_next_event_pos(log_file_name, m_binlog_file->position());
7209 }
7210 5927057 }
7211
7212 /*
7213 Moves the last bunch of rows from the pending Rows event to a cache (either
7214 transactional cache if is_transaction is @c true, or the non-transactional
7215 cache otherwise. Sets a new pending event.
7216
7217 @param thd a pointer to the user thread.
7218 @param evt a pointer to the row event.
7219 @param is_transactional @c true indicates a transactional cache,
7220 otherwise @c false a non-transactional.
7221 */
7222 36467307 int MYSQL_BIN_LOG::flush_and_set_pending_rows_event(THD *thd,
7223 Rows_log_event *event,
7224 bool is_transactional) {
7225
1/2
✓ Branch 0 taken 36467899 times.
✗ Branch 1 not taken.
36467307 DBUG_TRACE;
7226
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 36467823 times.
36467899 assert(mysql_bin_log.is_open());
7227
5/8
✓ Branch 0 taken 36467615 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 36467683 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 30 times.
✓ Branch 5 taken 36467653 times.
✓ Branch 6 taken 30 times.
✗ Branch 7 not taken.
36467823 DBUG_PRINT("enter", ("event: %p", event));
7228
7229 36467683 int error = 0;
7230
1/2
✓ Branch 0 taken 36467824 times.
✗ Branch 1 not taken.
36467683 binlog_cache_mngr *const cache_mngr = thd_get_cache_mngr(thd);
7231
7232
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 36467824 times.
36467824 assert(cache_mngr);
7233
7234 binlog_cache_data *cache_data =
7235 36467824 cache_mngr->get_binlog_cache_data(is_transactional);
7236
7237
5/8
✓ Branch 0 taken 36467742 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 36467911 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 30 times.
✓ Branch 5 taken 36467881 times.
✓ Branch 6 taken 30 times.
✗ Branch 7 not taken.
36467877 DBUG_PRINT("info", ("cache_mngr->pending(): %p", cache_data->pending()));
7238
7239
2/2
✓ Branch 0 taken 26038195 times.
✓ Branch 1 taken 10429598 times.
36467911 if (Rows_log_event *pending = cache_data->pending()) {
7240 /*
7241 Write pending event to the cache.
7242 */
7243
3/4
✓ Branch 0 taken 26038204 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 26038196 times.
26038195 if (cache_data->write_event(pending)) {
7244
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 report_cache_write_error(thd, is_transactional);
7245
5/8
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 5 times.
✓ Branch 7 taken 3 times.
16 if (check_write_error(thd) && cache_data &&
7246
3/4
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 3 times.
8 stmt_cannot_safely_rollback(thd))
7247 5 cache_data->set_incident();
7248
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 delete pending;
7249 8 cache_data->set_pending(nullptr);
7250 8 return 1;
7251 }
7252
7253
2/2
✓ Branch 0 taken 26038070 times.
✓ Branch 1 taken 126 times.
26038196 delete pending;
7254 }
7255
7256 36467887 cache_data->set_pending(event);
7257
7258 36467482 return error;
7259 36467490 }
7260
7261 /**
7262 Write an event to the binary log cache.
7263 */
7264
7265 824565 bool MYSQL_BIN_LOG::write_event(Log_event *event_info) {
7266 824565 THD *thd = event_info->thd;
7267 824565 bool error = true;
7268
1/2
✓ Branch 0 taken 824817 times.
✗ Branch 1 not taken.
824565 DBUG_TRACE;
7269
7270
2/2
✓ Branch 0 taken 15329 times.
✓ Branch 1 taken 809488 times.
824817 if (thd->binlog_evt_union.do_union) {
7271 /*
7272 In Stored function; Remember that function call caused an update.
7273 We will log the function call to the binary log on function exit
7274 */
7275 15329 thd->binlog_evt_union.unioned_events = true;
7276 15329 thd->binlog_evt_union.unioned_events_trans |=
7277 15329 event_info->is_using_trans_cache();
7278 15329 return false;
7279 }
7280
7281 /*
7282 We only end the statement if we are in a top-level statement. If
7283 we are inside a stored function, we do not end the statement since
7284 this will close all tables on the slave. But there can be a special case
7285 where we are inside a stored function/trigger and a SAVEPOINT is being
7286 set in side the stored function/trigger. This SAVEPOINT execution will
7287 force the pending event to be flushed without an STMT_END_F flag. This
7288 will result in a case where following DMLs will be considered as part of
7289 same statement and result in data loss on slave. Hence in this case we
7290 force the end_stmt to be true.
7291 */
7292 bool const end_stmt =
7293
2/2
✓ Branch 0 taken 1913 times.
✓ Branch 1 taken 21 times.
1934 (thd->in_sub_stmt && thd->lex->sql_command == SQLCOM_SAVEPOINT)
7294
2/2
✓ Branch 0 taken 1934 times.
✓ Branch 1 taken 807554 times.
1618976 ? true
7295
4/4
✓ Branch 0 taken 15133 times.
✓ Branch 1 taken 794334 times.
✓ Branch 2 taken 12686 times.
✓ Branch 3 taken 2447 times.
809467 : (thd->locked_tables_mode && thd->lex->requires_prelocking());
7296
2/4
✓ Branch 0 taken 809531 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 809531 times.
809325 if (thd->binlog_flush_pending_rows_event(end_stmt,
7297 809488 event_info->is_using_trans_cache()))
7298 return error;
7299
7300 /*
7301 In most cases this is only called if 'is_open()' is true; in fact this is
7302 mostly called if is_open() *was* true a few instructions before, but it
7303 could have changed since.
7304 */
7305
2/2
✓ Branch 0 taken 809433 times.
✓ Branch 1 taken 25 times.
809531 if (likely(is_open())) {
7306 /*
7307 In the future we need to add to the following if tests like
7308 "do the involved tables match (to be implemented)
7309 binlog_[wild_]{do|ignore}_table?" (WL#1049)"
7310 */
7311
1/2
✓ Branch 0 taken 809300 times.
✗ Branch 1 not taken.
809433 const char *local_db = event_info->get_db();
7312
5/6
✓ Branch 0 taken 809497 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 694611 times.
✓ Branch 3 taken 114886 times.
✓ Branch 4 taken 115159 times.
✓ Branch 5 taken 694293 times.
1503866 if ((thd && !(thd->variables.option_bits & OPTION_BIN_LOG)) ||
7313
1/2
✓ Branch 0 taken 694542 times.
✗ Branch 1 not taken.
694414 (thd->lex->sql_command != SQLCOM_ROLLBACK_TO_SAVEPOINT &&
7314
2/2
✓ Branch 0 taken 679404 times.
✓ Branch 1 taken 15138 times.
694542 thd->lex->sql_command != SQLCOM_SAVEPOINT &&
7315
2/2
✓ Branch 0 taken 679242 times.
✓ Branch 1 taken 162 times.
679404 (!event_info->is_no_filter_event() &&
7316
3/4
✓ Branch 0 taken 679394 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 273 times.
✓ Branch 3 taken 679121 times.
679242 !binlog_filter->db_ok(local_db))))
7317 115159 return false;
7318
7319
3/4
✓ Branch 0 taken 174220 times.
✓ Branch 1 taken 520093 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 174233 times.
694293 assert(event_info->is_using_trans_cache() ||
7320 event_info->is_using_stmt_cache());
7321
7322
2/4
✓ Branch 0 taken 694304 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 694304 times.
694326 if (binlog_start_trans_and_stmt(thd, event_info)) return error;
7323
7324 694304 bool is_trans_cache = event_info->is_using_trans_cache();
7325
1/2
✓ Branch 0 taken 694367 times.
✗ Branch 1 not taken.
694306 binlog_cache_mngr *cache_mngr = thd_get_cache_mngr(thd);
7326 binlog_cache_data *cache_data =
7327 694367 cache_mngr->get_binlog_cache_data(is_trans_cache);
7328
7329
5/8
✓ Branch 0 taken 694310 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 694312 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 91 times.
✓ Branch 5 taken 694221 times.
✓ Branch 6 taken 98 times.
✗ Branch 7 not taken.
694365 DBUG_PRINT("info", ("event type: %d", event_info->get_type_code()));
7330
7331 /*
7332 No check for auto events flag here - this write method should
7333 never be called if auto-events are enabled.
7334
7335 Write first log events which describe the 'run environment'
7336 of the SQL command. If row-based binlogging, Insert_id, Rand
7337 and other kind of "setting context" events are not needed.
7338 */
7339
1/2
✓ Branch 0 taken 694319 times.
✗ Branch 1 not taken.
694319 if (thd) {
7340
2/2
✓ Branch 0 taken 391606 times.
✓ Branch 1 taken 302701 times.
694319 if (!thd->is_current_stmt_binlog_format_row()) {
7341
2/2
✓ Branch 0 taken 185 times.
✓ Branch 1 taken 391421 times.
391606 if (thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt) {
7342 Intvar_log_event e(
7343 thd, (uchar)binary_log::Intvar_event::LAST_INSERT_ID_EVENT,
7344 thd->first_successful_insert_id_in_prev_stmt_for_binlog,
7345
1/2
✓ Branch 0 taken 185 times.
✗ Branch 1 not taken.
185 event_info->event_cache_type, event_info->event_logging_type);
7346
2/4
✓ Branch 0 taken 185 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 185 times.
185 if (cache_data->write_event(&e)) goto err;
7347
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 184 times.
185 if (event_info->is_using_immediate_logging())
7348 1 thd->binlog_bytes_written += e.header()->data_written;
7349
1/2
✓ Branch 0 taken 185 times.
✗ Branch 1 not taken.
185 }
7350
2/2
✓ Branch 0 taken 87334 times.
✓ Branch 1 taken 304123 times.
391606 if (thd->auto_inc_intervals_in_cur_stmt_for_binlog.nb_elements() > 0) {
7351
3/8
✓ Branch 0 taken 87334 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 87334 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 87334 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
87334 DBUG_PRINT(
7352 "info",
7353 ("number of auto_inc intervals: %u",
7354 thd->auto_inc_intervals_in_cur_stmt_for_binlog.nb_elements()));
7355 Intvar_log_event e(
7356 thd, (uchar)binary_log::Intvar_event::INSERT_ID_EVENT,
7357 thd->auto_inc_intervals_in_cur_stmt_for_binlog.minimum(),
7358
1/2
✓ Branch 0 taken 87334 times.
✗ Branch 1 not taken.
87334 event_info->event_cache_type, event_info->event_logging_type);
7359
2/4
✓ Branch 0 taken 87334 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 87334 times.
87334 if (cache_data->write_event(&e)) goto err;
7360
2/2
✓ Branch 0 taken 68 times.
✓ Branch 1 taken 87266 times.
87334 if (event_info->is_using_immediate_logging())
7361 68 thd->binlog_bytes_written += e.header()->data_written;
7362
1/2
✓ Branch 0 taken 87334 times.
✗ Branch 1 not taken.
87334 }
7363
2/2
✓ Branch 0 taken 2098 times.
✓ Branch 1 taken 389359 times.
391457 if (thd->rand_used) {
7364 2098 Rand_log_event e(thd, thd->rand_saved_seed1, thd->rand_saved_seed2,
7365 event_info->event_cache_type,
7366
1/2
✓ Branch 0 taken 2098 times.
✗ Branch 1 not taken.
2098 event_info->event_logging_type);
7367
2/4
✓ Branch 0 taken 2098 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2098 times.
2098 if (cache_data->write_event(&e)) goto err;
7368
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2098 times.
2098 if (event_info->is_using_immediate_logging())
7369 thd->binlog_bytes_written += e.header()->data_written;
7370
1/2
✓ Branch 0 taken 2098 times.
✗ Branch 1 not taken.
2098 }
7371
3/4
✓ Branch 0 taken 391440 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8445 times.
✓ Branch 3 taken 382995 times.
391457 if (!thd->user_var_events.empty()) {
7372
3/4
✓ Branch 0 taken 16964 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8519 times.
✓ Branch 3 taken 8445 times.
16964 for (size_t i = 0; i < thd->user_var_events.size(); i++) {
7373
1/2
✓ Branch 0 taken 8519 times.
✗ Branch 1 not taken.
8519 Binlog_user_var_event *user_var_event = thd->user_var_events[i];
7374
7375 /* setting flags for user var log event */
7376 8519 uchar flags = User_var_log_event::UNDEF_F;
7377
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 8508 times.
8519 if (user_var_event->unsigned_flag)
7378 11 flags |= User_var_log_event::UNSIGNED_F;
7379
7380 User_var_log_event e(
7381 8519 thd, user_var_event->user_var_event->entry_name.ptr(),
7382 8519 user_var_event->user_var_event->entry_name.length(),
7383 user_var_event->value, user_var_event->length,
7384 user_var_event->type, user_var_event->charset_number, flags,
7385
1/2
✓ Branch 0 taken 8519 times.
✗ Branch 1 not taken.
8519 event_info->event_cache_type, event_info->event_logging_type);
7386
2/4
✓ Branch 0 taken 8519 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 8519 times.
8519 if (cache_data->write_event(&e)) goto err;
7387
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 8489 times.
8519 if (event_info->is_using_immediate_logging())
7388 30 thd->binlog_bytes_written += e.header()->data_written;
7389
1/2
✓ Branch 0 taken 8519 times.
✗ Branch 1 not taken.
8519 }
7390 }
7391 }
7392 }
7393
7394 /*
7395 Write the event.
7396 */
7397
3/4
✓ Branch 0 taken 694309 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 53 times.
✓ Branch 3 taken 694256 times.
694141 if (cache_data->write_event(event_info)) goto err;
7398
7399
3/4
✓ Branch 0 taken 694274 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 36 times.
✓ Branch 3 taken 694238 times.
694256 if (DBUG_EVALUATE_IF("injecting_fault_writing", 1, 0)) goto err;
7400
2/2
✓ Branch 0 taken 103641 times.
✓ Branch 1 taken 590612 times.
694238 if (event_info->is_using_immediate_logging())
7401 103641 thd->binlog_bytes_written += event_info->common_header->data_written;
7402
7403 /*
7404 After writing the event, if the trx-cache was used and any unsafe
7405 change was written into it, the cache is marked as cannot safely
7406 roll back.
7407 */
7408
7/8
✓ Branch 0 taken 520021 times.
✓ Branch 1 taken 174232 times.
✓ Branch 2 taken 520013 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1160 times.
✓ Branch 5 taken 518853 times.
✓ Branch 6 taken 1160 times.
✓ Branch 7 taken 693085 times.
694253 if (is_trans_cache && stmt_cannot_safely_rollback(thd))
7409 1160 cache_mngr->trx_cache.set_cannot_rollback();
7410
7411 694237 error = false;
7412
7413 694326 err:
7414
2/2
✓ Branch 0 taken 89 times.
✓ Branch 1 taken 694237 times.
694326 if (error) {
7415
1/2
✓ Branch 0 taken 89 times.
✗ Branch 1 not taken.
89 report_cache_write_error(thd, is_trans_cache);
7416
5/8
✓ Branch 0 taken 89 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 89 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 89 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 4 times.
✓ Branch 7 taken 85 times.
178 if (check_write_error(thd) && cache_data &&
7417
3/4
✓ Branch 0 taken 89 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 85 times.
89 stmt_cannot_safely_rollback(thd))
7418 4 cache_data->set_incident();
7419 }
7420 }
7421
7422 694248 return error;
7423 824736 }
7424
7425 /**
7426 The method executes rotation when LOCK_log is already acquired
7427 by the caller.
7428
7429 @param force_rotate caller can request the log rotation
7430 @param check_purge is set to true if rotation took place
7431
7432 @note
7433 If rotation fails, for instance the server was unable
7434 to create a new log file, we still try to write an
7435 incident event to the current log.
7436
7437 @note The caller must hold LOCK_log when invoking this function.
7438
7439 @retval
7440 nonzero - error in rotating routine.
7441 */
7442 15035 int MYSQL_BIN_LOG::rotate(bool force_rotate, bool *check_purge) {
7443 15035 int error = 0;
7444
1/2
✓ Branch 0 taken 15035 times.
✗ Branch 1 not taken.
15035 DBUG_TRACE;
7445
7446
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15035 times.
15035 assert(!is_relay_log);
7447 15035 mysql_mutex_assert_owner(&LOCK_log);
7448
7449 15035 *check_purge = false;
7450
7451
3/4
✓ Branch 0 taken 15035 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12246 times.
✓ Branch 3 taken 2786 times.
30067 if (DBUG_EVALUATE_IF("force_rotate", 1, 0) || force_rotate ||
7452
6/6
✓ Branch 0 taken 15032 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 5295 times.
✓ Branch 3 taken 6951 times.
✓ Branch 4 taken 9741 times.
✓ Branch 5 taken 5294 times.
35362 (m_binlog_file->get_real_file_size() >= (my_off_t)max_size) ||
7453
3/4
✓ Branch 0 taken 5295 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 5294 times.
5295 DBUG_EVALUATE_IF("simulate_max_binlog_size", true, false)) {
7454
1/2
✓ Branch 0 taken 9726 times.
✗ Branch 1 not taken.
9741 error = new_file_without_locking(nullptr);
7455 9726 *check_purge = true;
7456
1/2
✓ Branch 0 taken 9726 times.
✗ Branch 1 not taken.
9726 publish_coordinates_for_global_status();
7457 }
7458 15020 return error;
7459 15020 }
7460
7461 11221 void MYSQL_BIN_LOG::auto_purge_at_server_startup() {
7462 // first run the auto purge validations
7463
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 11215 times.
11221 if (check_auto_purge_conditions()) return;
7464
7465 11215 auto purge_time = calculate_auto_purge_lower_time_bound();
7466 11215 constexpr auto auto_purge{true};
7467 11215 purge_logs_before_date(purge_time, auto_purge);
7468 }
7469
7470 /**
7471 The method executes logs purging routine.
7472 */
7473 8703 void MYSQL_BIN_LOG::auto_purge() {
7474 // first run the auto purge validations
7475
3/4
✓ Branch 0 taken 8703 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✓ Branch 3 taken 8680 times.
8734 if (check_auto_purge_conditions()) return;
7476
7477 // then we run the purge validations
7478 // if we run into out of memory, execute binlog_error_action_abort
7479
1/2
✓ Branch 0 taken 8680 times.
✗ Branch 1 not taken.
8680 const auto [is_invalid_purge, purge_error] = check_purge_conditions(*this);
7480
2/2
✓ Branch 0 taken 31 times.
✓ Branch 1 taken 8649 times.
8680 if (is_invalid_purge) {
7481
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 31 times.
31 if (purge_error == LOG_INFO_MEM) {
7482 /* purecov: begin inspected */
7483 // OOM
7484 exec_binlog_error_action_abort(
7485 "Out of memory happened while checking if "
7486 "instance was locked for backup");
7487 /* purecov: end */
7488 }
7489 31 return;
7490 }
7491
7492
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8649 times.
8649 assert(purge_error == 0);
7493
7494
3/6
✓ Branch 0 taken 8649 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8649 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8649 times.
✗ Branch 5 not taken.
8649 DEBUG_SYNC(current_thd, "at_purge_logs_before_date");
7495
7496
1/2
✓ Branch 0 taken 8649 times.
✗ Branch 1 not taken.
8649 auto purge_time = calculate_auto_purge_lower_time_bound();
7497 8649 constexpr auto auto_purge{true};
7498 /*
7499 Flush logs for storage engines, so that the last transaction
7500 is persisted inside storage engines.
7501 */
7502
1/2
✓ Branch 0 taken 8649 times.
✗ Branch 1 not taken.
8649 ha_flush_logs();
7503
1/2
✓ Branch 0 taken 8649 times.
✗ Branch 1 not taken.
8649 purge_logs_before_date(purge_time, auto_purge);
7504
7505
3/4
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 8607 times.
✓ Branch 2 taken 42 times.
✗ Branch 3 not taken.
8649 if (binlog_space_limit) purge_logs_by_size(true);
7506 }
7507
7508 /**
7509 Execute a FLUSH LOGS statement.
7510
7511 The method is a shortcut of @c rotate() and @c purge().
7512 LOCK_log is acquired prior to rotate and is released after it.
7513
7514 @param thd Current session.
7515 @param force_rotate caller can request the log rotation
7516
7517 @retval
7518 nonzero - error in rotating routine.
7519 */
7520 1752 int MYSQL_BIN_LOG::rotate_and_purge(THD *thd, bool force_rotate) {
7521 1752 int error = 0;
7522
1/2
✓ Branch 0 taken 1752 times.
✗ Branch 1 not taken.
1752 DBUG_TRACE;
7523 1752 bool check_purge = false;
7524
7525 /*
7526 FLUSH BINARY LOGS command should ignore 'read-only' and 'super_read_only'
7527 options so that it can update 'mysql.gtid_executed' replication repository
7528 table.
7529 */
7530 1752 thd->set_skip_readonly_check();
7531 /*
7532 Wait for handlerton to insert any pending information into the binlog.
7533 For e.g. ha_ndbcluster which updates the binlog asynchronously this is
7534 needed so that the user see its own commands in the binlog.
7535 */
7536
1/2
✓ Branch 0 taken 1752 times.
✗ Branch 1 not taken.
1752 ha_binlog_wait(thd);
7537
7538
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1752 times.
1752 assert(!is_relay_log);
7539
1/2
✓ Branch 0 taken 1752 times.
✗ Branch 1 not taken.
1752 mysql_mutex_lock(&LOCK_log);
7540
1/2
✓ Branch 0 taken 1737 times.
✗ Branch 1 not taken.
1752 error = rotate(force_rotate, &check_purge);
7541 /*
7542 NOTE: Run purge_logs wo/ holding LOCK_log because it does not need
7543 the mutex. Otherwise causes various deadlocks.
7544 */
7545
1/2
✓ Branch 0 taken 1737 times.
✗ Branch 1 not taken.
1737 mysql_mutex_unlock(&LOCK_log);
7546
7547
4/6
✓ Branch 0 taken 1712 times.
✓ Branch 1 taken 25 times.
✓ Branch 2 taken 1712 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1712 times.
✗ Branch 5 not taken.
1737 if (!error && check_purge) auto_purge();
7548
7549 1737 return error;
7550 1737 }
7551
7552 4133 uint MYSQL_BIN_LOG::next_file_id() {
7553 uint res;
7554 4133 mysql_mutex_lock(&LOCK_log);
7555 4133 res = file_id++;
7556 4133 mysql_mutex_unlock(&LOCK_log);
7557 4133 return res;
7558 }
7559
7560 13774 int MYSQL_BIN_LOG::get_gtid_executed(Sid_map *sid_map, Gtid_set *gtid_set) {
7561
1/2
✓ Branch 0 taken 13774 times.
✗ Branch 1 not taken.
13774 DBUG_TRACE;
7562 13774 int error = 0;
7563
7564
1/2
✓ Branch 0 taken 13774 times.
✗ Branch 1 not taken.
13774 mysql_mutex_lock(&mysql_bin_log.LOCK_commit);
7565
1/2
✓ Branch 0 taken 13774 times.
✗ Branch 1 not taken.
13774 global_sid_lock->wrlock();
7566
7567
1/2
✓ Branch 0 taken 13774 times.
✗ Branch 1 not taken.
13774 enum_return_status return_status = global_sid_map->copy(sid_map);
7568
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13774 times.
13774 if (return_status != RETURN_STATUS_OK) {
7569 error = 1;
7570 goto end;
7571 }
7572
7573
1/2
✓ Branch 0 taken 13774 times.
✗ Branch 1 not taken.
13774 return_status = gtid_set->add_gtid_set(gtid_state->get_executed_gtids());
7574
1/2
✓ Branch 0 taken 13774 times.
✗ Branch 1 not taken.
13774 if (return_status != RETURN_STATUS_OK) error = 1;
7575
7576 13774 end:
7577
1/2
✓ Branch 0 taken 13774 times.
✗ Branch 1 not taken.
13774 global_sid_lock->unlock();
7578
1/2
✓ Branch 0 taken 13774 times.
✗ Branch 1 not taken.
13774 mysql_mutex_unlock(&mysql_bin_log.LOCK_commit);
7579
7580 13774 return error;
7581 13774 }
7582
7583 /**
7584 Write the contents of the given IO_CACHE to the binary log.
7585
7586 The cache will be reset as a READ_CACHE to be able to read the
7587 contents from it.
7588
7589 The data will be post-processed: see class Binlog_event_writer for
7590 details.
7591
7592 @param cache Events will be read from this IO_CACHE.
7593 @param writer Events will be written to this Binlog_event_writer.
7594
7595 @retval true IO error.
7596 @retval false Success.
7597
7598 @see MYSQL_BIN_LOG::write_cache
7599 */
7600 5927063 bool MYSQL_BIN_LOG::do_write_cache(Binlog_cache_storage *cache,
7601 Binlog_event_writer *writer) {
7602
1/2
✓ Branch 0 taken 5927063 times.
✗ Branch 1 not taken.
5927063 DBUG_TRACE;
7603
7604
4/6
✓ Branch 0 taken 5927063 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 5927062 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
5927063 DBUG_EXECUTE_IF("simulate_do_write_cache_failure", {
7605 /*
7606 see binlog_cache_data::write_event() that reacts on
7607 @c simulate_disk_full_at_flush_pending.
7608 */
7609 DBUG_SET("-d,simulate_do_write_cache_failure");
7610 return true;
7611 });
7612
7613 #ifndef NDEBUG
7614
1/2
✓ Branch 0 taken 5927062 times.
✗ Branch 1 not taken.
5927062 uint64 expected_total_len = cache->length();
7615
5/8
✓ Branch 0 taken 5927062 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5927062 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 106 times.
✓ Branch 5 taken 5926956 times.
✓ Branch 6 taken 106 times.
✗ Branch 7 not taken.
5927062 DBUG_PRINT("info", ("bytes in cache= %" PRIu64, expected_total_len));
7616 #endif
7617
7618 5927062 bool error = false;
7619
3/4
✓ Branch 0 taken 5927062 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 5927060 times.
5927062 if (cache->copy_to(writer, &error)) {
7620
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
2 if (error) report_binlog_write_error();
7621 2 return true;
7622 }
7623 5927060 return false;
7624 5927063 }
7625
7626 /**
7627 Writes an incident event to stmt_cache.
7628
7629 @param ev Incident event to be written
7630 @param thd Thread variable
7631 @param need_lock_log If true, will acquire LOCK_log; otherwise the
7632 caller should already have acquired LOCK_log.
7633 @param err_msg Error message written to log file for the incident.
7634 @param do_flush_and_sync If true, will call flush_and_sync(), rotate() and
7635 purge().
7636
7637 @retval false error
7638 @retval true success
7639 */
7640 11 bool MYSQL_BIN_LOG::write_incident(Incident_log_event *ev, THD *thd,
7641 bool need_lock_log, const char *err_msg,
7642 bool do_flush_and_sync) {
7643 11 uint error = 0;
7644
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 DBUG_TRACE;
7645
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 assert(err_msg);
7646
7647
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (!is_open()) return error;
7648
7649
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 binlog_cache_mngr *cache_mngr = thd_get_cache_mngr(thd);
7650
7651 /*
7652 thd->cache_mngr may be uninitialized when first transaction resulted in an
7653 incident. If there is no cache manager exists for the session, then we
7654 create one, so that a GTID is generated and is written prior to flushing
7655 the stmt_cache.
7656 */
7657
3/4
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 10 times.
22 if (cache_mngr == nullptr ||
7658
3/4
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 10 times.
11 DBUG_EVALUATE_IF("simulate_cache_creation_failure", 1, 0)) {
7659
3/6
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
2 if (thd->binlog_setup_trx_data() ||
7660
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 DBUG_EVALUATE_IF("simulate_cache_creation_failure", 1, 0)) {
7661
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 auto gtid_mode = global_gtid_mode.get();
7662
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 if (gtid_mode == Gtid_mode::ON || gtid_mode == Gtid_mode::ON_PERMISSIVE) {
7663
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 std::ostringstream message;
7664
7665 message << "Could not create IO cache while writing an incident event "
7666
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 "to the binary log. Since GTID_MODE = "
7667
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 << gtid_mode
7668
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 << ", server is unable to proceed with logging. Query: '";
7669 /**
7670 The reason for the error may be that the query was
7671 huge. Better cut it to not run into resource problems.
7672 */
7673
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 message.write(thd->query().str, MYSQL_ERRMSG_SIZE);
7674
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 message << "'.";
7675
7676
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 handle_binlog_flush_or_sync_error(thd, true, message.str().c_str());
7677 1 return true;
7678 1 }
7679 } else
7680 cache_mngr = thd_get_cache_mngr(thd);
7681 }
7682
7683 #ifndef NDEBUG
7684
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 if (DBUG_EVALUATE_IF("simulate_write_incident_event_into_binlog_directly", 1,
7685
4/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 9 times.
11 0) &&
7686
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 !cache_mngr->stmt_cache.is_binlog_empty()) {
7687 /* The stmt_cache contains corruption data, so we can reset it. */
7688
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 cache_mngr->stmt_cache.reset();
7689 }
7690 #endif
7691
7692 /*
7693 If there is no binlog cache then we write incidents directly
7694 into the binlog. If caller needs GTIDs it has to setup the
7695 binlog cache (for the injector thread).
7696 */
7697
3/4
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 9 times.
20 if (cache_mngr == nullptr ||
7698
3/4
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 9 times.
10 DBUG_EVALUATE_IF("simulate_write_incident_event_into_binlog_directly", 1,
7699 0)) {
7700
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (need_lock_log)
7701
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 mysql_mutex_lock(&LOCK_log);
7702 else
7703 mysql_mutex_assert_owner(&LOCK_log);
7704 /* Write an incident event into binlog directly. */
7705
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 error = write_event_to_binlog(ev);
7706 /*
7707 Write an error to log. So that user might have a chance
7708 to be alerted and explore incident details.
7709 */
7710
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (!error)
7711
8/16
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 1 times.
✗ Branch 15 not taken.
1 LogErr(ERROR_LEVEL, ER_BINLOG_LOGGING_INCIDENT_TO_STOP_SLAVES, err_msg);
7712 } else // (cache_mngr != NULL)
7713 {
7714
3/4
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 3 times.
9 if (!cache_mngr->stmt_cache.is_binlog_empty()) {
7715 /* The stmt_cache contains corruption data, so we can reset it. */
7716
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 cache_mngr->stmt_cache.reset();
7717 }
7718
3/4
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 6 times.
9 if (!cache_mngr->trx_cache.is_binlog_empty()) {
7719 /* The trx_cache contains corruption data, so we can reset it. */
7720
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 cache_mngr->trx_cache.reset();
7721 }
7722 /*
7723 Write the incident event into stmt_cache, so that a GTID is generated and
7724 written for it prior to flushing the stmt_cache.
7725 */
7726 9 binlog_cache_data *cache_data = cache_mngr->get_binlog_cache_data(false);
7727
3/6
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 9 times.
9 if ((error = cache_data->write_event(ev))) {
7728 LogErr(ERROR_LEVEL, ER_BINLOG_EVENT_WRITE_TO_STMT_CACHE_FAILED);
7729 cache_mngr->stmt_cache.reset();
7730 return error;
7731 }
7732
7733
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 2 times.
9 if (need_lock_log)
7734
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 mysql_mutex_lock(&LOCK_log);
7735 else
7736 2 mysql_mutex_assert_owner(&LOCK_log);
7737 }
7738
7739
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 2 times.
10 if (do_flush_and_sync) {
7740
4/8
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 8 times.
✗ Branch 7 not taken.
8 if (!error && !(error = flush_and_sync())) {
7741 8 bool check_purge = false;
7742
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 update_binlog_end_pos();
7743 8 is_rotating_caused_by_incident = true;
7744
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 error = rotate(true, &check_purge);
7745 8 is_rotating_caused_by_incident = false;
7746
3/6
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
8 if (!error && check_purge) auto_purge();
7747 }
7748 }
7749
7750
3/4
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
10 if (need_lock_log) mysql_mutex_unlock(&LOCK_log);
7751
7752 /*
7753 Write an error to log. So that user might have a chance
7754 to be alerted and explore incident details.
7755 */
7756
2/4
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
10 if (!error && cache_mngr != nullptr)
7757
8/16
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 10 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 10 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 10 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 10 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 10 times.
✗ Branch 15 not taken.
10 LogErr(ERROR_LEVEL, ER_BINLOG_LOGGING_INCIDENT_TO_STOP_SLAVES, err_msg);
7758
7759 10 return error;
7760 11 }
7761
7762 56 bool MYSQL_BIN_LOG::write_stmt_directly(THD *thd, const char *stmt,
7763 size_t stmt_len,
7764 enum_sql_command sql_command) {
7765 56 bool ret = false;
7766 /* backup the original command */
7767 56 enum_sql_command save_sql_command = thd->lex->sql_command;
7768 56 thd->lex->sql_command = sql_command;
7769
7770 56 if (thd->binlog_query(THD::STMT_QUERY_TYPE, stmt, stmt_len, false, false,
7771
2/4
✓ Branch 0 taken 56 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 56 times.
112 false, 0) ||
7772
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 56 times.
56 commit(thd, false) != TC_LOG::RESULT_SUCCESS) {
7773 ret = true;
7774 }
7775
7776 56 thd->lex->sql_command = save_sql_command;
7777 56 return ret;
7778 }
7779
7780 /**
7781 Creates an incident event and writes it to the binary log.
7782
7783 @param thd Thread variable
7784 @param need_lock_log If the binary lock should be locked or not
7785 @param err_msg Error message written to log file for the incident.
7786 @param do_flush_and_sync If true, will call flush_and_sync(), rotate() and
7787 purge().
7788
7789 @retval
7790 0 error
7791 @retval
7792 1 success
7793 */
7794 11 bool MYSQL_BIN_LOG::write_incident(THD *thd, bool need_lock_log,
7795 const char *err_msg,
7796 bool do_flush_and_sync) {
7797
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 DBUG_TRACE;
7798
7799
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (!is_open()) return false;
7800
7801 11 LEX_CSTRING write_error_msg = {err_msg, strlen(err_msg)};
7802 11 binary_log::Incident_event::enum_incident incident =
7803 binary_log::Incident_event::INCIDENT_LOST_EVENTS;
7804
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 Incident_log_event ev(thd, incident, write_error_msg);
7805
7806
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 return write_incident(&ev, thd, need_lock_log, err_msg, do_flush_and_sync);
7807 11 }
7808
7809 /*
7810 Write the event into current binlog directly without going though a session
7811 binlog cache. It will update the event's log_pos and set checksum accordingly.
7812 binary_event_serialize can be called directly if log_pos should not be
7813 updated.
7814 */
7815 221406 inline bool MYSQL_BIN_LOG::write_event_to_binlog(Log_event *ev) {
7816 221406 ev->common_footer->checksum_alg =
7817 221406 is_relay_log
7818
2/2
✓ Branch 0 taken 140715 times.
✓ Branch 1 taken 80691 times.
221406 ? relay_log_checksum_alg
7819 80691 : static_cast<enum_binlog_checksum_alg>(binlog_checksum_options);
7820
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 221406 times.
221406 assert(ev->common_footer->checksum_alg !=
7821 binary_log::BINLOG_CHECKSUM_ALG_UNDEF);
7822
7823 /*
7824 Stores current position into log_pos, it is used to calculate correctly
7825 end_log_pos by adding data_written in Log_event::write_header().
7826 */
7827 221406 ev->common_header->log_pos = m_binlog_file->position();
7828
7829
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 221406 times.
221406 if (binary_event_serialize(ev, m_binlog_file)) return true;
7830
7831 221406 add_bytes_written(ev->common_header->data_written);
7832 221405 return false;
7833 }
7834
7835 /* Write the event into current binlog and flush and sync */
7836 11221 bool MYSQL_BIN_LOG::write_event_to_binlog_and_sync(Log_event *ev) {
7837
3/6
✓ Branch 0 taken 11221 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11221 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 11221 times.
22442 if (write_event_to_binlog(ev) || m_binlog_file->flush() ||
7838
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11221 times.
11221 m_binlog_file->sync())
7839 return true;
7840
7841 11221 update_binlog_end_pos();
7842 11221 return false;
7843 }
7844
7845 /**
7846 Write the contents of the statement or transaction cache to the binary log.
7847
7848 Comparison with do_write_cache:
7849
7850 - do_write_cache is a lower-level function that only performs the
7851 actual write.
7852
7853 - write_cache is a higher-level function that calls do_write_cache
7854 and additionally performs some maintenance tasks, including:
7855 - report any errors that occurred
7856 - write incident event if needed
7857 - update gtid_state
7858 - update thd.binlog_next_event_pos
7859
7860 @param thd Thread variable
7861
7862 @param cache_data Events will be read from the IO_CACHE of this
7863 cache_data object.
7864
7865 @param writer Events will be written to this Binlog_event_writer.
7866
7867 @retval true IO error.
7868 @retval false Success.
7869
7870 @note We only come here if there is something in the cache.
7871 @note Whatever is in the cache is always a complete transaction.
7872 @note 'cache' needs to be reinitialized after this functions returns.
7873 */
7874 5927063 bool MYSQL_BIN_LOG::write_cache(THD *thd, binlog_cache_data *cache_data,
7875 Binlog_event_writer *writer) {
7876
1/2
✓ Branch 0 taken 5927063 times.
✗ Branch 1 not taken.
5927063 DBUG_TRACE;
7877
7878 5927063 Binlog_cache_storage *cache = cache_data->get_cache();
7879 5927063 bool incident = cache_data->has_incident();
7880
7881 5927063 mysql_mutex_assert_owner(&LOCK_log);
7882
7883
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5927063 times.
5927063 assert(is_open());
7884
1/2
✓ Branch 0 taken 5927063 times.
✗ Branch 1 not taken.
5927063 if (likely(is_open())) // Should always be true
7885 {
7886 /*
7887 We only bother to write to the binary log if there is anything
7888 to write.
7889
7890 @todo Is this check redundant? Probably this is only called if
7891 there is anything in the cache (see @note in comment above this
7892 function). Check if we can replace this by an assertion. /Sven
7893 */
7894
2/4
✓ Branch 0 taken 5927063 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5927063 times.
✗ Branch 3 not taken.
5927063 if (!cache->is_empty()) {
7895
2/28
✓ Branch 0 taken 5927063 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5927063 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
5927063 DBUG_EXECUTE_IF("crash_before_writing_xid", {
7896 if (do_write_cache(cache, writer))
7897 DBUG_PRINT("info", ("error writing binlog cache: %d", write_error));
7898 flush_and_sync(true);
7899 DBUG_PRINT("info", ("crashing before writing xid"));
7900 DBUG_SUICIDE();
7901 });
7902
3/4
✓ Branch 0 taken 5927063 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 5927060 times.
5927063 if (do_write_cache(cache, writer)) goto err;
7903
7904 5927060 const char *err_msg =
7905 "Non-transactional changes did not get into "
7906 "the binlog.";
7907
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 5927058 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5927060 times.
5927062 if (incident &&
7908
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
2 write_incident(thd, false /*need_lock_log=false*/, err_msg,
7909 false /*do_flush_and_sync==false*/)) {
7910 report_binlog_write_error();
7911 goto err;
7912 }
7913
4/6
✓ Branch 0 taken 5927060 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 5927057 times.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
5927060 DBUG_EXECUTE_IF("half_binlogged_transaction", DBUG_SUICIDE(););
7914 }
7915
1/2
✓ Branch 0 taken 5927057 times.
✗ Branch 1 not taken.
5927057 update_thd_next_event_pos(thd);
7916 }
7917
7918 5927057 return false;
7919
7920 3 err:
7921 3 thd->commit_error = THD::CE_FLUSH_ERROR;
7922
7923 3 return true;
7924 5927060 }
7925
7926 4 void MYSQL_BIN_LOG::report_binlog_write_error() {
7927 char errbuf[MYSYS_STRERROR_SIZE];
7928
7929 4 write_error = true;
7930
9/18
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 4 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 4 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 4 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 4 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 4 times.
✗ Branch 17 not taken.
4 LogErr(ERROR_LEVEL, ER_FAILED_TO_WRITE_TO_FILE, name, errno,
7931 my_strerror(errbuf, sizeof(errbuf), errno));
7932 4 }
7933
7934 /**
7935 Wait until we get a signal that the binary log has been updated.
7936 Applies to master only.
7937
7938 NOTES
7939 @param[in] timeout a pointer to a timespec;
7940 NULL means to wait w/o timeout.
7941 @retval 0 if got signalled on update
7942 @retval non-0 if wait timeout elapsed
7943 @note
7944 LOCK_binlog_end_pos must be taken before calling this function.
7945 LOCK_binlog_end_pos is being released while the thread is waiting.
7946 LOCK_binlog_end_pos is released by the caller.
7947 */
7948
7949 953536 int MYSQL_BIN_LOG::wait_for_update(const struct timespec *timeout) {
7950 953536 int ret = 0;
7951
1/2
✓ Branch 0 taken 953536 times.
✗ Branch 1 not taken.
953536 DBUG_TRACE;
7952
7953
2/2
✓ Branch 0 taken 139 times.
✓ Branch 1 taken 953397 times.
953536 if (!timeout)
7954
1/2
✓ Branch 0 taken 139 times.
✗ Branch 1 not taken.
139 mysql_cond_wait(&update_cond, &LOCK_binlog_end_pos);
7955 else
7956
1/2
✓ Branch 0 taken 953246 times.
✗ Branch 1 not taken.
953397 ret = mysql_cond_timedwait(&update_cond, &LOCK_binlog_end_pos,
7957 const_cast<struct timespec *>(timeout));
7958 953386 return ret;
7959 953385 }
7960
7961 /**
7962 Close the log file.
7963
7964 @param exiting Bitmask for one or more of the following bits:
7965 - LOG_CLOSE_INDEX : if we should close the index file
7966 - LOG_CLOSE_TO_BE_OPENED : if we intend to call open
7967 at once after close.
7968 - LOG_CLOSE_STOP_EVENT : write a 'stop' event to the log
7969
7970 @param need_lock_log If true, this function acquires LOCK_log;
7971 otherwise the caller should already have acquired it.
7972
7973 @param need_lock_index If true, this function acquires LOCK_index;
7974 otherwise the caller should already have acquired it.
7975
7976 @note
7977 One can do an open on the object at once after doing a close.
7978 The internal structures are not freed until cleanup() is called
7979 */
7980
7981 136834 void MYSQL_BIN_LOG::close(
7982 uint exiting, bool need_lock_log,
7983 bool need_lock_index) { // One can't set log_type here!
7984
1/2
✓ Branch 0 taken 136835 times.
✗ Branch 1 not taken.
136834 DBUG_TRACE;
7985
4/8
✓ Branch 0 taken 136835 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 136835 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 136834 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
136835 DBUG_PRINT("enter", ("exiting: %d", (int)exiting));
7986
2/2
✓ Branch 0 taken 42854 times.
✓ Branch 1 taken 93980 times.
136834 if (need_lock_log)
7987
1/2
✓ Branch 0 taken 42854 times.
✗ Branch 1 not taken.
42854 mysql_mutex_lock(&LOCK_log);
7988 else
7989 93980 mysql_mutex_assert_owner(&LOCK_log);
7990
7991
2/2
✓ Branch 0 taken 82555 times.
✓ Branch 1 taken 54280 times.
136835 if (atomic_log_state == LOG_OPENED) {
7992
2/2
✓ Branch 0 taken 18593 times.
✓ Branch 1 taken 63962 times.
82555 if ((exiting & LOG_CLOSE_STOP_EVENT) != 0) {
7993 /**
7994 TODO(WL#7546): Change the implementation to Stop_event after write() is
7995 moved into libbinlogevents
7996 */
7997
1/2
✓ Branch 0 taken 18593 times.
✗ Branch 1 not taken.
18593 Stop_log_event s;
7998 // the checksumming rule for relay-log case is similar to Rotate
7999 18593 s.common_footer->checksum_alg =
8000 18593 is_relay_log
8001
2/2
✓ Branch 0 taken 8914 times.
✓ Branch 1 taken 9679 times.
18593 ? relay_log_checksum_alg
8002 9679 : static_cast<enum_binlog_checksum_alg>(binlog_checksum_options);
8003
3/4
✓ Branch 0 taken 8914 times.
✓ Branch 1 taken 9679 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8914 times.
18593 assert(!is_relay_log ||
8004 relay_log_checksum_alg != binary_log::BINLOG_CHECKSUM_ALG_UNDEF);
8005
7/10
✓ Branch 0 taken 18593 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18593 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18593 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 18591 times.
✓ Branch 7 taken 2 times.
✓ Branch 8 taken 18591 times.
✓ Branch 9 taken 2 times.
18593 if (!write_event_to_binlog(&s) && !m_binlog_file->flush())
8006
1/2
✓ Branch 0 taken 18591 times.
✗ Branch 1 not taken.
18591 update_binlog_end_pos();
8007 18593 }
8008
8009 /* The following update should not be done in relay log files */
8010
2/2
✓ Branch 0 taken 29162 times.
✓ Branch 1 taken 53393 times.
82555 if (!is_relay_log) {
8011 29162 my_off_t offset = BIN_LOG_HEADER_SIZE + FLAGS_OFFSET;
8012 29162 uchar flags = 0; // clearing LOG_EVENT_BINLOG_IN_USE_F
8013
1/2
✓ Branch 0 taken 29162 times.
✗ Branch 1 not taken.
29162 (void)m_binlog_file->update(&flags, 1, offset);
8014 }
8015
8016
6/8
✓ Branch 0 taken 82555 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 82553 times.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 82553 times.
82555 if (m_binlog_file->flush_and_sync() && !write_error) {
8017
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 report_binlog_write_error();
8018 }
8019
8020 /*
8021 LOCK_sync to guarantee that no thread is calling m_binlog_file
8022 to sync data to disk when another thread is closing m_binlog_file.
8023 */
8024
3/4
✓ Branch 0 taken 29162 times.
✓ Branch 1 taken 53393 times.
✓ Branch 2 taken 29162 times.
✗ Branch 3 not taken.
82555 if (!is_relay_log) mysql_mutex_lock(&LOCK_sync);
8025 82555 m_binlog_file->close();
8026
3/4
✓ Branch 0 taken 29162 times.
✓ Branch 1 taken 53393 times.
✓ Branch 2 taken 29162 times.
✗ Branch 3 not taken.
82555 if (!is_relay_log) mysql_mutex_unlock(&LOCK_sync);
8027
8028 82555 atomic_log_state =
8029
2/2
✓ Branch 0 taken 63931 times.
✓ Branch 1 taken 18624 times.
82555 (exiting & LOG_CLOSE_TO_BE_OPENED) ? LOG_TO_BE_OPENED : LOG_CLOSED;
8030
1/2
✓ Branch 0 taken 82555 times.
✗ Branch 1 not taken.
82555 my_free(name);
8031 82555 name = nullptr;
8032 }
8033
8034 /*
8035 The following test is needed even if is_open() is not set, as we may have
8036 called a not complete close earlier and the index file is still open.
8037 */
8038
8039
2/2
✓ Branch 0 taken 42868 times.
✓ Branch 1 taken 93967 times.
136835 if (need_lock_index)
8040
1/2
✓ Branch 0 taken 42868 times.
✗ Branch 1 not taken.
42868 mysql_mutex_lock(&LOCK_index);
8041 else
8042 93967 mysql_mutex_assert_owner(&LOCK_index);
8043
8044
6/6
✓ Branch 0 taken 106848 times.
✓ Branch 1 taken 29987 times.
✓ Branch 2 taken 82764 times.
✓ Branch 3 taken 24084 times.
✓ Branch 4 taken 82764 times.
✓ Branch 5 taken 54071 times.
136835 if ((exiting & LOG_CLOSE_INDEX) && my_b_inited(&index_file)) {
8045
1/2
✓ Branch 0 taken 82764 times.
✗ Branch 1 not taken.
82764 end_io_cache(&index_file);
8046
6/8
✓ Branch 0 taken 82764 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 82762 times.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 82762 times.
82764 if (mysql_file_close(index_file.file, MYF(0)) < 0 && !write_error) {
8047
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 report_binlog_write_error();
8048 }
8049 }
8050
8051
3/4
✓ Branch 0 taken 42868 times.
✓ Branch 1 taken 93967 times.
✓ Branch 2 taken 42868 times.
✗ Branch 3 not taken.
136835 if (need_lock_index) mysql_mutex_unlock(&LOCK_index);
8052
8053 136835 atomic_log_state =
8054
2/2
✓ Branch 0 taken 93916 times.
✓ Branch 1 taken 42919 times.
136835 (exiting & LOG_CLOSE_TO_BE_OPENED) ? LOG_TO_BE_OPENED : LOG_CLOSED;
8055
1/2
✓ Branch 0 taken 136835 times.
✗ Branch 1 not taken.
136835 my_free(name);
8056 136835 name = nullptr;
8057
8058
3/4
✓ Branch 0 taken 42854 times.
✓ Branch 1 taken 93981 times.
✓ Branch 2 taken 42854 times.
✗ Branch 3 not taken.
136835 if (need_lock_log) mysql_mutex_unlock(&LOCK_log);
8059 136835 }
8060
8061 1802860 void MYSQL_BIN_LOG::harvest_bytes_written(Relay_log_info *rli,
8062 bool need_log_space_lock) {
8063 #ifndef NDEBUG
8064 char buf1[22], buf2[22];
8065 #endif
8066
8067
1/2
✓ Branch 0 taken 1802860 times.
✗ Branch 1 not taken.
1802860 DBUG_TRACE;
8068
2/2
✓ Branch 0 taken 1802828 times.
✓ Branch 1 taken 32 times.
1802860 if (need_log_space_lock)
8069
1/2
✓ Branch 0 taken 1802828 times.
✗ Branch 1 not taken.
1802828 mysql_mutex_lock(&rli->log_space_lock);
8070 else
8071 32 mysql_mutex_assert_owner(&rli->log_space_lock);
8072 1802860 rli->log_space_total += bytes_written;
8073
3/12
✓ Branch 0 taken 1802860 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1802860 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1802860 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
1802860 DBUG_PRINT("info",
8074 ("relay_log_space: %s bytes_written: %s",
8075 llstr(rli->log_space_total, buf1), llstr(bytes_written, buf2)));
8076 1802860 bytes_written = 0;
8077
3/4
✓ Branch 0 taken 1802828 times.
✓ Branch 1 taken 32 times.
✓ Branch 2 taken 1802828 times.
✗ Branch 3 not taken.
1802860 if (need_log_space_lock) mysql_mutex_unlock(&rli->log_space_lock);
8078 1802860 }
8079
8080 219 void MYSQL_BIN_LOG::set_max_size(ulong max_size_arg) {
8081 /*
8082 We need to take locks, otherwise this may happen:
8083 new_file() is called, calls open(old_max_size), then before open() starts,
8084 set_max_size() sets max_size to max_size_arg, then open() starts and
8085 uses the old_max_size argument, so max_size_arg has been overwritten and
8086 it's like if the SET command was never run.
8087 */
8088
1/2
✓ Branch 0 taken 219 times.
✗ Branch 1 not taken.
219 DBUG_TRACE;
8089
1/2
✓ Branch 0 taken 219 times.
✗ Branch 1 not taken.
219 mysql_mutex_lock(&LOCK_log);
8090
2/2
✓ Branch 0 taken 112 times.
✓ Branch 1 taken 107 times.
219 if (is_open()) max_size = max_size_arg;
8091
1/2
✓ Branch 0 taken 219 times.
✗ Branch 1 not taken.
219 mysql_mutex_unlock(&LOCK_log);
8092 219 }
8093
8094 /****** transaction coordinator log for 2pc - binlog() based solution ******/
8095
8096 /**
8097 @todo
8098 keep in-memory list of prepared transactions
8099 (add to list in log(), remove on unlog())
8100 and copy it to the new binlog if rotated
8101 but let's check the behaviour of tc_log_page_waits first!
8102 */
8103
8104 11321 int MYSQL_BIN_LOG::open_binlog(const char *opt_name) {
8105 11321 LOG_INFO log_info;
8106 11321 int error = 1;
8107 11321 bool should_execute_ha_recover{false};
8108
8109 /*
8110 This function is used for 2pc transaction coordination. Hence, it
8111 is never used for relay logs.
8112 */
8113
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11321 times.
11321 assert(!is_relay_log);
8114
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 11321 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
11321 assert(total_ha_2pc > 1 || (1 == total_ha_2pc && opt_bin_log));
8115
2/4
✓ Branch 0 taken 11321 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11321 times.
✗ Branch 3 not taken.
11321 assert(opt_name && opt_name[0]);
8116
8117
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11321 times.
11321 if (!my_b_inited(&index_file)) {
8118 /* There was a failure to open the index file, can't open the binlog */
8119 cleanup();
8120 return 1;
8121 }
8122
8123
3/4
✓ Branch 0 taken 11321 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 11319 times.
11321 if (using_heuristic_recover()) {
8124 /* generate a new binlog to mask a corrupted one */
8125
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 mysql_mutex_lock(&LOCK_log);
8126
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 open_binlog(opt_name, nullptr, max_binlog_size, false,
8127 true /*need_lock_index=true*/, true /*need_sid_lock=true*/,
8128 nullptr);
8129
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 mysql_mutex_unlock(&LOCK_log);
8130
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 cleanup();
8131 2 return 1;
8132 }
8133
8134
3/4
✓ Branch 0 taken 11319 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5096 times.
✓ Branch 3 taken 6223 times.
11319 if ((error = find_log_pos(&log_info, NullS, true /*need_lock_index=true*/))) {
8135
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5096 times.
5096 if (error != LOG_INFO_EOF)
8136 LogErr(ERROR_LEVEL, ER_BINLOG_CANT_FIND_LOG_IN_INDEX, error);
8137 else {
8138 5096 error = 0;
8139 5096 should_execute_ha_recover = true;
8140 }
8141 5096 goto err;
8142 }
8143
8144 {
8145 6223 Log_event *ev = nullptr;
8146 char log_name[FN_REFLEN];
8147 6223 my_off_t valid_pos = 0;
8148 6223 my_off_t binlog_size = 0;
8149
8150 do {
8151
1/2
✓ Branch 0 taken 169908 times.
✗ Branch 1 not taken.
169908 strmake(log_name, log_info.log_file_name, sizeof(log_name) - 1);
8152 } while (
8153
3/4
✓ Branch 0 taken 169908 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 163685 times.
✓ Branch 3 taken 6223 times.
169908 !(error = find_next_log(&log_info, true /*need_lock_index=true*/)));
8154
8155
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6223 times.
6223 if (error != LOG_INFO_EOF) {
8156 LogErr(ERROR_LEVEL, ER_BINLOG_CANT_FIND_LOG_IN_INDEX, error);
8157 4512 goto err;
8158 }
8159
8160
1/2
✓ Branch 0 taken 6223 times.
✗ Branch 1 not taken.
6223 Binlog_file_reader binlog_file_reader(opt_source_verify_checksum);
8161
3/4
✓ Branch 0 taken 6223 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 6210 times.
6223 if (binlog_file_reader.open(log_name)) {
8162
9/18
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 13 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 13 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 13 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 13 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 13 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 13 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 13 times.
✗ Branch 17 not taken.
13 LogErr(ERROR_LEVEL, ER_BINLOG_FILE_OPEN_FAILED,
8163 binlog_file_reader.get_error_str());
8164 13 goto err;
8165 }
8166
8167 /*
8168 If the binary log was not properly closed it means that the server
8169 may have crashed. In that case, we need to call
8170 binlog::Binlog_recovery::recover()
8171 to:
8172
8173 a) collect logged XIDs;
8174 b) complete the 2PC of the pending XIDs;
8175 c) collect the last valid position.
8176
8177 Therefore, we do need to iterate over the binary log, even if
8178 total_ha_2pc == 1, to find the last valid group of events written.
8179 Later we will take this value and truncate the log if need be.
8180 */
8181
2/4
✓ Branch 0 taken 6210 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6210 times.
✗ Branch 3 not taken.
12420 if ((ev = binlog_file_reader.read_event_object()) &&
8182
3/4
✓ Branch 0 taken 6210 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1774 times.
✓ Branch 3 taken 4436 times.
12420 ev->get_type_code() == binary_log::FORMAT_DESCRIPTION_EVENT &&
8183
2/2
✓ Branch 0 taken 4436 times.
✓ Branch 1 taken 1774 times.
6210 (ev->common_header->flags & LOG_EVENT_BINLOG_IN_USE_F ||
8184
2/4
✓ Branch 0 taken 4436 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4436 times.
4436 DBUG_EVALUATE_IF("eval_force_bin_log_recovery", true, false))) {
8185
8/16
✓ Branch 0 taken 1774 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1774 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1774 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1774 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1774 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1774 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 1774 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 1774 times.
✗ Branch 15 not taken.
1774 LogErr(INFORMATION_LEVEL, ER_BINLOG_RECOVERING_AFTER_CRASH_USING,
8186 opt_name);
8187
1/2
✓ Branch 0 taken 1774 times.
✗ Branch 1 not taken.
1774 binlog::Binlog_recovery bl_recovery{binlog_file_reader};
8188 1774 error = bl_recovery //
8189
1/2
✓ Branch 0 taken 1774 times.
✗ Branch 1 not taken.
1774 .recover() //
8190
1/2
✓ Branch 0 taken 1774 times.
✗ Branch 1 not taken.
1774 .has_failures();
8191
1/2
✓ Branch 0 taken 1774 times.
✗ Branch 1 not taken.
1774 valid_pos = bl_recovery.get_valid_pos();
8192
1/2
✓ Branch 0 taken 1774 times.
✗ Branch 1 not taken.
1774 binlog_size = binlog_file_reader.ifile()->length();
8193
2/2
✓ Branch 0 taken 63 times.
✓ Branch 1 taken 1711 times.
1774 if (error) {
8194
3/4
✓ Branch 0 taken 63 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 48 times.
63 if (bl_recovery.is_binlog_malformed())
8195
9/18
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 15 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 15 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 15 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 15 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 15 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 15 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 15 times.
✗ Branch 17 not taken.
15 LogErr(ERROR_LEVEL, ER_BINLOG_CRASH_RECOVERY_MALFORMED_LOG, log_name,
8196 valid_pos, binlog_file_reader.position(),
8197 bl_recovery.get_failure_message().data());
8198
3/4
✓ Branch 0 taken 63 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 48 times.
✓ Branch 3 taken 15 times.
63 if (bl_recovery.has_engine_recovery_failed())
8199
8/16
✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 48 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 48 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 48 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 48 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 48 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 48 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 48 times.
✗ Branch 15 not taken.
48 LogErr(ERROR_LEVEL, ER_BINLOG_CRASH_RECOVERY_ERROR_RETURNED_SE);
8200 }
8201 1774 } else
8202 4436 should_execute_ha_recover = true;
8203
8204
1/2
✓ Branch 0 taken 6210 times.
✗ Branch 1 not taken.
6210 delete ev;
8205
8206
2/2
✓ Branch 0 taken 4499 times.
✓ Branch 1 taken 1711 times.
6210 if (error) goto err;
8207
8208 /* Trim the crashed binlog file to last valid transaction
8209 or event (non-transaction) base on valid_pos. */
8210
1/2
✓ Branch 0 taken 1711 times.
✗ Branch 1 not taken.
1711 if (valid_pos > 0) {
8211 std::unique_ptr<Binlog_ofile> ofile(
8212
1/2
✓ Branch 0 taken 1711 times.
✗ Branch 1 not taken.
1711 Binlog_ofile::open_existing(key_file_binlog, log_name, MYF(MY_WME)));
8213
8214
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1711 times.
1711 if (!ofile) {
8215 LogErr(ERROR_LEVEL, ER_BINLOG_CANT_OPEN_CRASHED_BINLOG);
8216 return -1;
8217 }
8218
8219 /* Change binlog file size to valid_pos */
8220
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 1705 times.
1711 if (valid_pos < binlog_size) {
8221
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
6 if (ofile->truncate(valid_pos)) {
8222 LogErr(ERROR_LEVEL, ER_BINLOG_CANT_TRIM_CRASHED_BINLOG);
8223 return -1;
8224 }
8225
8/16
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 6 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 6 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 6 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 6 times.
✗ Branch 15 not taken.
6 LogErr(INFORMATION_LEVEL, ER_BINLOG_CRASHED_BINLOG_TRIMMED, log_name,
8226 binlog_size, valid_pos, valid_pos);
8227 }
8228
8229 /* Clear LOG_EVENT_BINLOG_IN_USE_F */
8230 1711 uchar flags = 0;
8231
2/4
✓ Branch 0 taken 1711 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1711 times.
1711 if (ofile->update(&flags, 1, BIN_LOG_HEADER_SIZE + FLAGS_OFFSET)) {
8232 LogErr(ERROR_LEVEL,
8233 ER_BINLOG_CANT_CLEAR_IN_USE_FLAG_FOR_CRASHED_BINLOG);
8234 return -1;
8235 }
8236
1/2
✓ Branch 0 taken 1711 times.
✗ Branch 1 not taken.
1711 } // end if (valid_pos > 0)
8237
2/3
✓ Branch 0 taken 1711 times.
✓ Branch 1 taken 4512 times.
✗ Branch 2 not taken.
6223 }
8238
8239 11319 err:
8240
2/2
✓ Branch 0 taken 9532 times.
✓ Branch 1 taken 1787 times.
11319 if (should_execute_ha_recover) {
8241
1/2
✓ Branch 0 taken 9532 times.
✗ Branch 1 not taken.
9532 error = ha_recover();
8242
1/18
✗ Branch 0 not taken.
✓ Branch 1 taken 9532 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
9532 if (error) LogErr(ERROR_LEVEL, ER_BINLOG_CRASH_RECOVERY_ERROR_RETURNED_SE);
8243 }
8244 11319 return error;
8245 }
8246
8247 /**
8248 Truncate the active relay log file in the specified position.
8249
8250 @param mi Master_info of the channel going to truncate the relay log file.
8251 @param truncate_pos The position to truncate the active relay log file.
8252 @return False on success and true on failure.
8253 */
8254 6 bool MYSQL_BIN_LOG::truncate_relaylog_file(Master_info *mi,
8255 my_off_t truncate_pos) {
8256
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 DBUG_TRACE;
8257
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 assert(is_relay_log);
8258 6 mysql_mutex_assert_owner(&LOCK_log);
8259 6 Relay_log_info *rli = mi->rli;
8260 6 bool error = false;
8261
8262 /*
8263 If the relay log was closed by an error (binlog_error_action=IGNORE_ERROR)
8264 this truncate function should produce no result as the relay log is already
8265 in really bad shape.
8266 */
8267
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!is_open()) {
8268 return false;
8269 }
8270
8271 6 my_off_t relaylog_file_size = m_binlog_file->position();
8272
8273
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
6 if (truncate_pos > 0 && truncate_pos < relaylog_file_size) {
8274
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
6 if (m_binlog_file->truncate(truncate_pos)) {
8275 mi->report(ERROR_LEVEL, ER_SLAVE_RELAY_LOG_WRITE_FAILURE,
8276 ER_THD(current_thd, ER_SLAVE_RELAY_LOG_WRITE_FAILURE),
8277 "failed to truncate relay log file");
8278 error = true;
8279 } else {
8280
8/16
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 6 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 6 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 6 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 6 times.
✗ Branch 15 not taken.
6 LogErr(INFORMATION_LEVEL, ER_SLAVE_RELAY_LOG_TRUNCATE_INFO, log_file_name,
8281 relaylog_file_size, truncate_pos);
8282
8283 // Re-init the SQL thread IO_CACHE
8284
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
6 assert(strcmp(rli->get_event_relay_log_name(), log_file_name) ||
8285 rli->get_event_relay_log_pos() <= truncate_pos);
8286
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 rli->notify_relay_log_truncated();
8287 }
8288 }
8289 6 return error;
8290 6 }
8291
8292 /** This is called on shutdown, after ha_panic. */
8293 void MYSQL_BIN_LOG::close() {}
8294
8295 /*
8296 Prepare the transaction in the transaction coordinator.
8297
8298 This function will prepare the transaction in the storage engines
8299 (by calling @c ha_prepare_low) what will write a prepare record
8300 to the log buffers.
8301
8302 @retval 0 success
8303 @retval 1 error
8304 */
8305 11112138 int MYSQL_BIN_LOG::prepare(THD *thd, bool all) {
8306
1/2
✓ Branch 0 taken 11112682 times.
✗ Branch 1 not taken.
11112138 DBUG_TRACE;
8307
8308
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11112682 times.
11112682 assert(opt_bin_log);
8309
8310 /*
8311 Set HA_IGNORE_DURABILITY to not flush the prepared record of the
8312 transaction to the log of storage engine (for example, InnoDB
8313 redo log) during the prepare phase. So that we can flush prepared
8314 records of transactions to the log of storage engine in a group
8315 right before flushing them to binary log during binlog group
8316 commit flush stage. Reset to HA_REGULAR_DURABILITY at the
8317 beginning of parsing next command.
8318 */
8319 11112682 thd->durability_property = HA_IGNORE_DURABILITY;
8320
8321
2/4
✓ Branch 0 taken 11112719 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11112625 times.
✗ Branch 3 not taken.
11112682 CONDITIONAL_SYNC_POINT_FOR_TIMESTAMP("before_prepare_in_engines");
8322
1/2
✓ Branch 0 taken 11112691 times.
✗ Branch 1 not taken.
11112763 int error = ha_prepare_low(thd, all);
8323
8324
2/4
✓ Branch 0 taken 11112773 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11112828 times.
✗ Branch 3 not taken.
11112691 CONDITIONAL_SYNC_POINT_FOR_TIMESTAMP("after_ha_prepare_low");
8325 // Invoke `commit` if we're dealing with `XA PREPARE` in order to use BCG
8326 // to write the event to file.
8327
10/12
✓ Branch 0 taken 11112531 times.
✓ Branch 1 taken 291 times.
✓ Branch 2 taken 501073 times.
✓ Branch 3 taken 10611458 times.
✓ Branch 4 taken 501072 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 571 times.
✓ Branch 7 taken 500501 times.
✓ Branch 8 taken 571 times.
✓ Branch 9 taken 11112250 times.
✓ Branch 10 taken 568 times.
✗ Branch 11 not taken.
11112822 if (!error && all && is_xa_prepare(thd)) return this->commit(thd, true);
8328
8329 11112250 return error;
8330 11112818 }
8331
8332 /**
8333 Commit the transaction in the transaction coordinator.
8334
8335 This function will commit the sessions transaction in the binary log
8336 and in the storage engines (by calling @c ha_commit_low). If the
8337 transaction was successfully logged (or not successfully unlogged)
8338 but the commit in the engines did not succeed, there is a risk of
8339 inconsistency between the engines and the binary log.
8340
8341 For binary log group commit, the commit is separated into three
8342 parts:
8343
8344 1. First part consists of filling the necessary caches and
8345 finalizing them (if they need to be finalized). After this,
8346 nothing is added to any of the caches.
8347
8348 2. Second part execute an ordered flush and commit. This will be
8349 done using the group commit functionality in ordered_commit.
8350
8351 3. Third part checks any errors resulting from the ordered commit
8352 and handles them appropriately.
8353
8354 @retval RESULT_SUCCESS success
8355 @retval RESULT_ABORTED error, transaction was neither logged nor committed
8356 @retval RESULT_INCONSISTENT error, transaction was logged but not committed
8357 */
8358 39471675 TC_LOG::enum_result MYSQL_BIN_LOG::commit(THD *thd, bool all) {
8359
1/2
✓ Branch 0 taken 39474548 times.
✗ Branch 1 not taken.
39471675 DBUG_TRACE;
8360
8/14
✓ Branch 0 taken 39473777 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 39474178 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 604 times.
✓ Branch 5 taken 39473574 times.
✓ Branch 6 taken 604 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 604 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 604 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 604 times.
✗ Branch 13 not taken.
39474548 DBUG_PRINT("info",
8361 ("query='%s'", thd == current_thd ? thd->query().str : nullptr));
8362 39474178 Transaction_ctx *trn_ctx = thd->get_transaction();
8363
1/2
✓ Branch 0 taken 39473046 times.
✗ Branch 1 not taken.
39473651 my_xid xid = trn_ctx->xid_state()->get_xid()->get_my_xid();
8364 39473046 bool stmt_stuff_logged = false;
8365 39473046 bool trx_stuff_logged = false;
8366
1/2
✓ Branch 0 taken 39473845 times.
✗ Branch 1 not taken.
39473046 bool skip_commit = is_loggable_xa_prepare(thd);
8367 39473845 bool is_atomic_ddl = false;
8368 39473845 auto xs = thd->get_transaction()->xid_state();
8369 39472552 raii::Sentry<> reset_detached_guard{[&]() -> void {
8370 // XID_STATE may have been used to hold metadata for a detached transaction.
8371 // In that case, we need to reset it.
8372
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39473270 times.
39472552 if (xs->is_detached()) xs->reset();
8373
1/2
✓ Branch 0 taken 39472930 times.
✗ Branch 1 not taken.
39474400 }};
8374
8375
2/2
✓ Branch 0 taken 1082 times.
✓ Branch 1 taken 39471906 times.
39472988 if (thd->lex->sql_command ==
8376 SQLCOM_XA_COMMIT) { // XA commit must be written to the binary log prior
8377 // to retrieving cache manager
8378
2/4
✓ Branch 0 taken 1082 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1082 times.
1082 if (this->write_xa_to_cache(thd)) return RESULT_ABORTED;
8379 }
8380
8381
1/2
✓ Branch 0 taken 39473416 times.
✗ Branch 1 not taken.
39472988 binlog_cache_mngr *cache_mngr = thd_get_cache_mngr(thd);
8382
7/10
✓ Branch 0 taken 39473217 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 39473513 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 596 times.
✓ Branch 5 taken 39472917 times.
✓ Branch 6 taken 287 times.
✓ Branch 7 taken 309 times.
✓ Branch 8 taken 655 times.
✗ Branch 9 not taken.
39473416 DBUG_PRINT("enter", ("thd: 0x%llx, all: %s, xid: %llu, cache_mngr: 0x%llx",
8383 (ulonglong)thd, YESNO(all), (ulonglong)xid,
8384 (ulonglong)cache_mngr));
8385
8386 /*
8387 No cache manager means nothing to log, but we still have to commit
8388 the transaction.
8389 */
8390
2/2
✓ Branch 0 taken 10726980 times.
✓ Branch 1 taken 28746598 times.
39473578 if (cache_mngr == nullptr) {
8391
7/8
✓ Branch 0 taken 10726922 times.
✓ Branch 1 taken 58 times.
✓ Branch 2 taken 10726844 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 10726841 times.
✓ Branch 6 taken 3 times.
✓ Branch 7 taken 10726899 times.
10726980 if (!skip_commit && trx_coordinator::commit_in_engines(thd, all))
8392 3 return RESULT_ABORTED;
8393 10726899 return RESULT_SUCCESS;
8394 }
8395
8396 /*
8397 Reset binlog_snapshot_% variables for the current connection so that the
8398 current coordinates are shown after committing a consistent snapshot
8399 transaction.
8400 */
8401
2/2
✓ Branch 0 taken 1874746 times.
✓ Branch 1 taken 26871852 times.
28746598 if (all) {
8402
1/2
✓ Branch 0 taken 1874760 times.
✗ Branch 1 not taken.
1874746 mysql_mutex_lock(&thd->LOCK_thd_data);
8403 1874760 cache_mngr->drop_consistent_snapshot();
8404
1/2
✓ Branch 0 taken 1874565 times.
✗ Branch 1 not taken.
1874775 mysql_mutex_unlock(&thd->LOCK_thd_data);
8405 }
8406
8407 28746417 Transaction_ctx::enum_trx_scope trx_scope =
8408
2/2
✓ Branch 0 taken 1874788 times.
✓ Branch 1 taken 26871629 times.
28746417 all ? Transaction_ctx::SESSION : Transaction_ctx::STMT;
8409
8410
8/12
✓ Branch 0 taken 28746701 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 28746861 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 586 times.
✓ Branch 5 taken 28746275 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 586 times.
✓ Branch 8 taken 563 times.
✓ Branch 9 taken 23 times.
✓ Branch 10 taken 586 times.
✗ Branch 11 not taken.
28746417 DBUG_PRINT("debug", ("in_transaction: %s, no_2pc: %s, rw_ha_count: %d",
8411 YESNO(thd->in_multi_stmt_transaction_mode()),
8412 YESNO(trn_ctx->no_2pc(trx_scope)),
8413 trn_ctx->rw_ha_count(trx_scope)));
8414
10/14
✓ Branch 0 taken 28746816 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 28746918 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 586 times.
✓ Branch 5 taken 28746332 times.
✓ Branch 6 taken 586 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 414 times.
✓ Branch 9 taken 172 times.
✓ Branch 10 taken 16 times.
✓ Branch 11 taken 570 times.
✓ Branch 12 taken 586 times.
✗ Branch 13 not taken.
28746861 DBUG_PRINT("debug",
8415 ("all.cannot_safely_rollback(): %s, trx_cache_empty: %s",
8416 YESNO(trn_ctx->cannot_safely_rollback(Transaction_ctx::SESSION)),
8417 YESNO(cache_mngr->trx_cache.is_binlog_empty())));
8418
10/14
✓ Branch 0 taken 28746886 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 28746969 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 586 times.
✓ Branch 5 taken 28746383 times.
✓ Branch 6 taken 586 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 562 times.
✓ Branch 9 taken 24 times.
✓ Branch 10 taken 9 times.
✓ Branch 11 taken 577 times.
✓ Branch 12 taken 284 times.
✗ Branch 13 not taken.
28746918 DBUG_PRINT("debug",
8419 ("stmt.cannot_safely_rollback(): %s, stmt_cache_empty: %s",
8420 YESNO(trn_ctx->cannot_safely_rollback(Transaction_ctx::STMT)),
8421 YESNO(cache_mngr->stmt_cache.is_binlog_empty())));
8422
8423 /*
8424 If there are no handlertons registered, there is nothing to
8425 commit. Note that DDLs are written earlier in this case (inside
8426 binlog_query).
8427
8428 TODO: This can be a problem in those cases that there are no
8429 handlertons registered. DDLs are one example, but the other case
8430 is MyISAM. In this case, we could register a dummy handlerton to
8431 trigger the commit.
8432
8433 Any statement that requires logging will call binlog_query before
8434 trans_commit_stmt, so an alternative is to use the condition
8435 "binlog_query called or stmt.ha_list != 0".
8436 */
8437
6/6
✓ Branch 0 taken 26872010 times.
✓ Branch 1 taken 1874659 times.
✓ Branch 2 taken 14795863 times.
✓ Branch 3 taken 12076154 times.
✓ Branch 4 taken 14696967 times.
✓ Branch 5 taken 14049882 times.
43542705 if (!all && !trn_ctx->is_active(trx_scope) &&
8438
3/4
✓ Branch 0 taken 14796036 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14697023 times.
✓ Branch 3 taken 99013 times.
14795863 cache_mngr->stmt_cache.is_binlog_empty())
8439 14696967 return RESULT_SUCCESS;
8440
8441
3/4
✓ Branch 0 taken 14050026 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 480856 times.
✓ Branch 3 taken 13569170 times.
14049882 if (!cache_mngr->stmt_cache.is_binlog_empty()) {
8442 /*
8443 Commit parent identification of non-transactional query has
8444 been deferred until now, except for the mixed transaction case.
8445 */
8446
1/2
✓ Branch 0 taken 480912 times.
✗ Branch 1 not taken.
480856 trn_ctx->store_commit_parent(
8447 m_dependency_tracker.get_max_committed_timestamp());
8448
2/4
✓ Branch 0 taken 480887 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 480887 times.
480567 if (cache_mngr->stmt_cache.finalize(thd)) return RESULT_ABORTED;
8449 480887 stmt_stuff_logged = true;
8450 }
8451
8452 /*
8453 We commit the transaction if:
8454 - We are not in a transaction and committing a statement, or
8455 - We are in a transaction and a full transaction is committed.
8456 Otherwise, we accumulate the changes.
8457 */
8458
8/10
✓ Branch 0 taken 14050155 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11410165 times.
✓ Branch 3 taken 2639990 times.
✓ Branch 4 taken 11410214 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 5445456 times.
✓ Branch 7 taken 5964758 times.
✓ Branch 8 taken 5445461 times.
✓ Branch 9 taken 8604743 times.
19495513 if (!cache_mngr->trx_cache.is_binlog_empty() && ending_trans(thd, all) &&
8459
1/2
✓ Branch 0 taken 5445462 times.
✗ Branch 1 not taken.
5445456 !trx_stuff_logged) {
8460 const bool real_trans =
8461
3/4
✓ Branch 0 taken 4891938 times.
✓ Branch 1 taken 553523 times.
✓ Branch 2 taken 4891943 times.
✗ Branch 3 not taken.
5445461 (all || !trn_ctx->is_active(Transaction_ctx::SESSION));
8462
8463
1/2
✓ Branch 0 taken 5445412 times.
✗ Branch 1 not taken.
5445462 bool one_phase = get_xa_opt(thd) == XA_ONE_PHASE;
8464
1/2
✓ Branch 0 taken 5445381 times.
✗ Branch 1 not taken.
5445412 bool is_loggable_xa = is_loggable_xa_prepare(thd);
8465
8466 /*
8467 Log and finalize transaction cache regarding XA PREPARE/XA COMMIT ONE
8468 PHASE if one of the following statements is true:
8469 - If it is a loggable XA transaction in prepare state;
8470 - If it is a transaction being committed with 'XA COMMIT ONE PHASE',
8471 statement and is not an empty transaction when GTID_NEXT is set to a
8472 manual GTID.
8473
8474 For other XA COMMIT ONE PHASE statements that already have been finalized
8475 or are finalizing empty transactions when GTID_NEXT is set to a manual
8476 GTID, just let the execution flow get into the final 'else' branch and log
8477 a final 'COMMIT;' statement.
8478 */
8479
4/4
✓ Branch 0 taken 5444845 times.
✓ Branch 1 taken 536 times.
✓ Branch 2 taken 634 times.
✓ Branch 3 taken 5444747 times.
10890226 if (is_loggable_xa || // XA transaction in prepare state
8480
3/4
✓ Branch 0 taken 101 times.
✓ Branch 1 taken 5444744 times.
✓ Branch 2 taken 101 times.
✗ Branch 3 not taken.
5444845 (thd->lex->sql_command == SQLCOM_XA_COMMIT && // Is a 'XA COMMIT
8481 101 one_phase && // ONE PHASE'
8482
1/2
✓ Branch 0 taken 101 times.
✗ Branch 1 not taken.
101 xs != nullptr && // and it has not yet
8483
1/2
✓ Branch 0 taken 101 times.
✗ Branch 1 not taken.
101 !xs->is_binlogged() && // been logged
8484
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 86 times.
101 (thd->owned_gtid.sidno <= 0 || // and GTID_NEXT is NOT set to a
8485 // manual GTID
8486
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 3 times.
15 !xs->has_state(XID_STATE::XA_NOTR)))) // and the transaction is NOT
8487 // empty and NOT finalized in
8488 // 'trans_xa_commit'
8489 {
8490 /* The prepare phase of XA transaction two phase logging. */
8491 634 int err = 0;
8492
8493
3/4
✓ Branch 0 taken 98 times.
✓ Branch 1 taken 536 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 98 times.
634 assert(thd->lex->sql_command != SQLCOM_XA_COMMIT || one_phase);
8494
8495
1/2
✓ Branch 0 taken 634 times.
✗ Branch 1 not taken.
634 XA_prepare_log_event end_evt(thd, xs->get_xid(), one_phase);
8496
8497
3/4
✓ Branch 0 taken 536 times.
✓ Branch 1 taken 98 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 536 times.
634 assert(!is_loggable_xa || skip_commit);
8498
8499
1/2
✓ Branch 0 taken 634 times.
✗ Branch 1 not taken.
634 err = cache_mngr->trx_cache.finalize(thd, &end_evt, xs);
8500
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 634 times.
634 if (err) return RESULT_ABORTED;
8501
2/2
✓ Branch 0 taken 536 times.
✓ Branch 1 taken 98 times.
634 if (is_loggable_xa)
8502
3/4
✓ Branch 0 taken 536 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 530 times.
536 if (DBUG_EVALUATE_IF("simulate_xa_prepare_failure_in_cache_finalize",
8503 true, false))
8504 6 return RESULT_ABORTED;
8505
2/2
✓ Branch 0 taken 628 times.
✓ Branch 1 taken 6 times.
634 }
8506 /*
8507 If is atomic DDL, finalize cache for DDL and no further logging is needed.
8508 */
8509
2/2
✓ Branch 0 taken 265647 times.
✓ Branch 1 taken 5179026 times.
5444747 else if ((is_atomic_ddl = cache_mngr->trx_cache.has_xid())) {
8510
2/4
✓ Branch 0 taken 265647 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 265647 times.
265647 if (cache_mngr->trx_cache.finalize(thd, nullptr)) return RESULT_ABORTED;
8511 }
8512 /*
8513 We are committing a 2PC transaction if it is a "real" transaction
8514 and has an XID assigned (because some handlerton registered). A
8515 transaction is "real" if either 'all' is true or
8516 'trn_ctx->is_active(Transaction_ctx::SESSION)' is not true.
8517
8518 Note: This is kind of strange since registering the binlog
8519 handlerton will then make the transaction 2PC, which is not really
8520 true. This occurs for example if a MyISAM statement is executed
8521 with row-based replication on.
8522 */
8523
8/8
✓ Branch 0 taken 5179023 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 5148953 times.
✓ Branch 3 taken 30070 times.
✓ Branch 4 taken 5119962 times.
✓ Branch 5 taken 29001 times.
✓ Branch 6 taken 5119957 times.
✓ Branch 7 taken 59067 times.
10298976 else if (real_trans && xid && trn_ctx->rw_ha_count(trx_scope) > 1 &&
8524
2/2
✓ Branch 0 taken 5119936 times.
✓ Branch 1 taken 14 times.
5119962 !trn_ctx->no_2pc(trx_scope)) {
8525
1/2
✓ Branch 0 taken 5119978 times.
✗ Branch 1 not taken.
5119957 Xid_log_event end_evt(thd, xid);
8526
2/4
✓ Branch 0 taken 5120162 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5120162 times.
5119978 if (cache_mngr->trx_cache.finalize(thd, &end_evt)) return RESULT_ABORTED;
8527
1/2
✓ Branch 0 taken 5120010 times.
✗ Branch 1 not taken.
5120162 }
8528 /*
8529 No further action needed and no special case applies, log a final
8530 'COMMIT' statement and finalize the transaction cache.
8531
8532 Empty transactions finalized with 'XA COMMIT ONE PHASE' will be covered
8533 by this branch.
8534 */
8535 else {
8536 Query_log_event end_evt(thd, STRING_WITH_LEN("COMMIT"), true, false, true,
8537
1/2
✓ Branch 0 taken 59088 times.
✗ Branch 1 not taken.
59067 0, true);
8538
2/4
✓ Branch 0 taken 59088 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 59088 times.
59088 if (cache_mngr->trx_cache.finalize(thd, &end_evt)) return RESULT_ABORTED;
8539
1/2
✓ Branch 0 taken 59088 times.
✗ Branch 1 not taken.
59088 }
8540 5445373 trx_stuff_logged = true;
8541 }
8542
8543 /*
8544 This is part of the stmt rollback.
8545 */
8546
3/4
✓ Branch 0 taken 12175171 times.
✓ Branch 1 taken 1874945 times.
✓ Branch 2 taken 12175453 times.
✗ Branch 3 not taken.
14050116 if (!all) cache_mngr->trx_cache.set_prev_position(MY_OFF_T_UNDEF);
8547
8548 /*
8549 Now all the events are written to the caches, so we will commit
8550 the transaction in the engines. This is done using the group
8551 commit logic in ordered_commit, which will return when the
8552 transaction is committed.
8553
8554 If the commit in the engines fail, we still have something logged
8555 to the binary log so we have to report this as a "bad" failure
8556 (failed to commit, but logged something).
8557 */
8558
4/4
✓ Branch 0 taken 13569281 times.
✓ Branch 1 taken 481117 times.
✓ Branch 2 taken 5444887 times.
✓ Branch 3 taken 8124394 times.
14050398 if (stmt_stuff_logged || trx_stuff_logged) {
8559
2/4
✓ Branch 0 taken 5925680 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5925756 times.
✗ Branch 3 not taken.
5926004 CONDITIONAL_SYNC_POINT_FOR_TIMESTAMP("before_invoke_before_commit_hook");
8560
6/10
✓ Branch 0 taken 5925400 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5821673 times.
✓ Branch 3 taken 103727 times.
✓ Branch 4 taken 103771 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 103845 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 103851 times.
✗ Branch 9 not taken.
5925843 if (RUN_HOOK(
8561 transaction, before_commit,
8562 (thd, all, thd_get_cache_mngr(thd)->get_trx_cache(),
8563 thd_get_cache_mngr(thd)->get_stmt_cache(),
8564 max<my_off_t>(max_binlog_cache_size, max_binlog_stmt_cache_size),
8565
4/4
✓ Branch 0 taken 5925381 times.
✓ Branch 1 taken 143 times.
✓ Branch 2 taken 44 times.
✓ Branch 3 taken 5925586 times.
11851011 is_atomic_ddl)) ||
8566
2/4
✓ Branch 0 taken 5925487 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5925497 times.
5925381 DBUG_EVALUATE_IF("simulate_failure_in_before_commit_hook", true,
8567 false)) {
8568
1/2
✓ Branch 0 taken 44 times.
✗ Branch 1 not taken.
44 trx_coordinator::rollback_in_engines(thd, all);
8569
1/2
✓ Branch 0 taken 44 times.
✗ Branch 1 not taken.
44 gtid_state->update_on_rollback(thd);
8570
2/4
✓ Branch 0 taken 44 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 44 times.
✗ Branch 3 not taken.
44 thd_get_cache_mngr(thd)->reset();
8571 // Reset the thread OK status before changing the outcome.
8572
2/2
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 15 times.
44 if (thd->get_stmt_da()->is_ok())
8573
1/2
✓ Branch 0 taken 29 times.
✗ Branch 1 not taken.
29 thd->get_stmt_da()->reset_diagnostics_area();
8574
1/2
✓ Branch 0 taken 44 times.
✗ Branch 1 not taken.
44 my_error(ER_RUN_HOOK_ERROR, MYF(0), "before_commit");
8575 44 return RESULT_ABORTED;
8576 }
8577 /*
8578 Check whether the transaction should commit or abort given the
8579 plugin feedback.
8580 */
8581 5925681 if (thd->get_transaction()
8582 ->get_rpl_transaction_ctx()
8583
5/6
✓ Branch 0 taken 5925755 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5925112 times.
✓ Branch 3 taken 643 times.
✓ Branch 4 taken 645 times.
✓ Branch 5 taken 5925036 times.
11850624 ->is_transaction_rollback() ||
8584
3/4
✓ Branch 0 taken 5925038 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 5925036 times.
5925112 (DBUG_EVALUATE_IF("simulate_transaction_rollback_request", true,
8585 false))) {
8586
1/2
✓ Branch 0 taken 645 times.
✗ Branch 1 not taken.
645 trx_coordinator::rollback_in_engines(thd, all);
8587
1/2
✓ Branch 0 taken 645 times.
✗ Branch 1 not taken.
645 gtid_state->update_on_rollback(thd);
8588
2/4
✓ Branch 0 taken 645 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 645 times.
✗ Branch 3 not taken.
645 thd_get_cache_mngr(thd)->reset();
8589
2/2
✓ Branch 0 taken 621 times.
✓ Branch 1 taken 24 times.
645 if (thd->get_stmt_da()->is_ok())
8590
1/2
✓ Branch 0 taken 621 times.
✗ Branch 1 not taken.
621 thd->get_stmt_da()->reset_diagnostics_area();
8591
1/2
✓ Branch 0 taken 645 times.
✗ Branch 1 not taken.
645 my_error(ER_TRANSACTION_ROLLBACK_DURING_COMMIT, MYF(0));
8592 645 return RESULT_ABORTED;
8593 }
8594
8595
1/2
✓ Branch 0 taken 5924878 times.
✗ Branch 1 not taken.
5925036 int rc = ordered_commit(thd, all, skip_commit);
8596
8597
2/2
✓ Branch 0 taken 82 times.
✓ Branch 1 taken 5924796 times.
5924878 if (rc) return RESULT_INCONSISTENT;
8598
8599
4/6
✓ Branch 0 taken 5924849 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 5924846 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
5924796 DBUG_EXECUTE_IF("ensure_binlog_cache_is_reset", {
8600 /* Assert that binlog cache is reset at commit time. */
8601 assert(binlog_cache_is_reset);
8602 binlog_cache_is_reset = false;
8603 };);
8604
8605 /*
8606 Mark the flag m_is_binlogged to true only after we are done
8607 with checking all the error cases.
8608 */
8609
3/4
✓ Branch 0 taken 5924806 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 527 times.
✓ Branch 3 taken 5924279 times.
5924849 if (is_loggable_xa_prepare(thd)) {
8610 527 thd->get_transaction()->xid_state()->set_binlogged();
8611 /*
8612 Inform hook listeners that a XA PREPARE did commit, that
8613 is, did log a transaction to the binary log.
8614 */
8615
4/6
✓ Branch 0 taken 527 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 84 times.
✓ Branch 3 taken 443 times.
✓ Branch 4 taken 85 times.
✗ Branch 5 not taken.
527 (void)RUN_HOOK(transaction, after_commit, (thd, all));
8616 }
8617
2/2
✓ Branch 0 taken 8124318 times.
✓ Branch 1 taken 76 times.
14049201 } else if (!skip_commit) {
8618 /*
8619 We only set engine binlog position in ordered_commit path flush phase
8620 and not all transactions go through them (such as table copy in DDL).
8621 So in cases where a DDL statement implicitly commits earlier transaction
8622 and starting a new one, the new transaction could be "leaking" the
8623 engine binlog pos. In order to avoid that and accidentally overwrite
8624 binlog position with previous location, we reset it here.
8625 */
8626
1/2
✓ Branch 0 taken 8124449 times.
✗ Branch 1 not taken.
8124318 thd->set_trans_pos(nullptr, 0);
8627
3/4
✓ Branch 0 taken 8124395 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 8124381 times.
8124449 if (trx_coordinator::commit_in_engines(thd, all))
8628 14 return RESULT_INCONSISTENT;
8629 }
8630
8631 14049264 return RESULT_SUCCESS;
8632 39473922 }
8633
8634 /**
8635 Flush caches for session.
8636
8637 @note @c set_trans_pos is called with a pointer to the file name
8638 that the binary log currently use and a rotation will change the
8639 contents of the variable.
8640
8641 The position is used when calling the after_flush, after_commit,
8642 and after_rollback hooks, but these have been placed so that they
8643 occur before a rotation is executed.
8644
8645 It is the responsibility of any plugin that use this position to
8646 copy it if they need it after the hook has returned.
8647
8648 The current "global" transaction_counter is stepped and its new value
8649 is assigned to the transaction.
8650 */
8651 5926417 std::pair<int, my_off_t> MYSQL_BIN_LOG::flush_thread_caches(THD *thd) {
8652
1/2
✓ Branch 0 taken 5926417 times.
✗ Branch 1 not taken.
5926417 binlog_cache_mngr *cache_mngr = thd_get_cache_mngr(thd);
8653 5926417 my_off_t bytes = 0;
8654 5926417 bool wrote_xid = false;
8655
1/2
✓ Branch 0 taken 5926414 times.
✗ Branch 1 not taken.
5926417 int error = cache_mngr->flush(thd, &bytes, &wrote_xid);
8656
3/4
✓ Branch 0 taken 5926410 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 5926410 times.
✗ Branch 3 not taken.
5926414 if (!error && bytes > 0) {
8657 /*
8658 Note that set_trans_pos does not copy the file name. See
8659 this function documentation for more info.
8660 */
8661
1/2
✓ Branch 0 taken 5926410 times.
✗ Branch 1 not taken.
5926410 thd->set_trans_pos(log_file_name, m_binlog_file->position());
8662
3/4
✓ Branch 0 taken 5385682 times.
✓ Branch 1 taken 540728 times.
✓ Branch 2 taken 5385682 times.
✗ Branch 3 not taken.
5926410 if (wrote_xid) inc_prep_xids(thd);
8663 }
8664
5/8
✓ Branch 0 taken 5926414 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5926414 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 100 times.
✓ Branch 5 taken 5926314 times.
✓ Branch 6 taken 100 times.
✗ Branch 7 not taken.
5926414 DBUG_PRINT("debug", ("bytes: %llu", bytes));
8665
1/2
✓ Branch 0 taken 5926414 times.
✗ Branch 1 not taken.
11852828 return std::make_pair(error, bytes);
8666 }
8667
8668 5925933 void MYSQL_BIN_LOG::init_thd_variables(THD *thd, bool all, bool skip_commit) {
8669 /*
8670 These values are used while committing a transaction, so clear
8671 everything.
8672
8673 Notes:
8674
8675 - It would be good if we could keep transaction coordinator
8676 log-specific data out of the THD structure, but that is not the
8677 case right now.
8678
8679 - Everything in the transaction structure is reset when calling
8680 ha_commit_low since that calls Transaction_ctx::cleanup.
8681 */
8682 5925933 thd->tx_commit_pending = true;
8683 5925933 thd->commit_error = THD::CE_NONE;
8684 5925933 thd->next_to_commit = nullptr;
8685 5925933 thd->durability_property = HA_IGNORE_DURABILITY;
8686 5925933 thd->get_transaction()->m_flags.real_commit = all;
8687 5926190 thd->get_transaction()->m_flags.xid_written = false;
8688 5926393 thd->get_transaction()->m_flags.commit_low = !skip_commit;
8689 5926397 thd->get_transaction()->m_flags.run_hooks = !skip_commit;
8690 #ifndef NDEBUG
8691 /*
8692 The group commit Leader may have to wait for follower whose transaction
8693 is not ready to be preempted. Initially the status is pessimistic.
8694 Preemption guarding logics is necessary only when !NDEBUG is set.
8695 It won't be required for the dbug-off case as long as the follower won't
8696 execute any thread-specific write access code in this method, which is
8697 the case as of current.
8698 */
8699 5926313 thd->get_transaction()->m_flags.ready_preempt = false;
8700 #endif
8701 5926382 }
8702
8703 5823420 THD *MYSQL_BIN_LOG::fetch_and_process_flush_stage_queue(
8704 const bool check_and_skip_flush_logs) {
8705 /*
8706 Fetch the entire flush queue and empty it, so that the next batch
8707 has a leader. We must do this before invoking ha_flush_logs(...)
8708 for guaranteeing to flush prepared records of transactions before
8709 flushing them to binary log, which is required by crash recovery.
8710 */
8711 5823420 Commit_stage_manager::get_instance().lock_queue(
8712 Commit_stage_manager::BINLOG_FLUSH_STAGE);
8713
8714 THD *first_seen =
8715 5823420 Commit_stage_manager::get_instance().fetch_queue_skip_acquire_lock(
8716 Commit_stage_manager::BINLOG_FLUSH_STAGE);
8717
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5823420 times.
5823420 assert(first_seen != nullptr);
8718
8719 THD *commit_order_thd =
8720 5823420 Commit_stage_manager::get_instance().fetch_queue_skip_acquire_lock(
8721 Commit_stage_manager::COMMIT_ORDER_FLUSH_STAGE);
8722
8723 5823420 Commit_stage_manager::get_instance().unlock_queue(
8724 Commit_stage_manager::BINLOG_FLUSH_STAGE);
8725
8726
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 5823419 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
5823420 if (!check_and_skip_flush_logs ||
8727
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 (check_and_skip_flush_logs && commit_order_thd != nullptr)) {
8728 /*
8729 We flush prepared records of transactions to the log of storage
8730 engine (for example, InnoDB redo log) in a group right before
8731 flushing them to binary log.
8732 */
8733 5823419 ha_flush_logs(true);
8734 }
8735
8736 /*
8737 The transactions are flushed to the disk and so threads
8738 executing slave preserve commit order can be unblocked.
8739 */
8740 5823413 Commit_stage_manager::get_instance()
8741 5823413 .process_final_stage_for_ordered_commit_group(commit_order_thd);
8742 5823413 return first_seen;
8743 }
8744
8745 5823419 int MYSQL_BIN_LOG::process_flush_stage_queue(my_off_t *total_bytes_var,
8746 bool *rotate_var,
8747 THD **out_queue_var) {
8748
1/2
✓ Branch 0 taken 5823419 times.
✗ Branch 1 not taken.
5823419 DBUG_TRACE;
8749 #ifndef NDEBUG
8750 // number of flushes per group.
8751 5823419 int no_flushes = 0;
8752 #endif
8753
3/6
✓ Branch 0 taken 5823419 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5823419 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5823419 times.
✗ Branch 5 not taken.
5823419 assert(total_bytes_var && rotate_var && out_queue_var);
8754 5823419 my_off_t total_bytes = 0;
8755 5823419 int flush_error = 1;
8756 5823419 mysql_mutex_assert_owner(&LOCK_log);
8757
8758
1/2
✓ Branch 0 taken 5823412 times.
✗ Branch 1 not taken.
5823419 THD *first_seen = fetch_and_process_flush_stage_queue();
8759
4/6
✓ Branch 0 taken 5823412 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 5823408 times.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
5823412 DBUG_EXECUTE_IF("crash_after_flush_engine_log", DBUG_SUICIDE(););
8760
2/4
✓ Branch 0 taken 5823408 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5823408 times.
✗ Branch 3 not taken.
5823408 CONDITIONAL_SYNC_POINT_FOR_TIMESTAMP("before_write_binlog");
8761
1/2
✓ Branch 0 taken 5823408 times.
✗ Branch 1 not taken.
5823408 assign_automatic_gtids_to_flush_group(first_seen);
8762 /* Flush thread caches to binary log. */
8763
2/2
✓ Branch 0 taken 5926417 times.
✓ Branch 1 taken 5823405 times.
11749822 for (THD *head = first_seen; head; head = head->next_to_commit) {
8764
2/4
✓ Branch 0 taken 5926417 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5926417 times.
✗ Branch 3 not taken.
5926417 Thd_backup_and_restore switch_thd(current_thd, head);
8765
1/2
✓ Branch 0 taken 5926414 times.
✗ Branch 1 not taken.
5926417 std::pair<int, my_off_t> result = flush_thread_caches(head);
8766 5926414 total_bytes += result.second;
8767
2/2
✓ Branch 0 taken 5823405 times.
✓ Branch 1 taken 103009 times.
5926414 if (flush_error == 1) flush_error = result.first;
8768 #ifndef NDEBUG
8769 5926414 no_flushes++;
8770 #endif
8771 5926414 }
8772
8773 5823405 *out_queue_var = first_seen;
8774 5823405 *total_bytes_var = total_bytes;
8775
4/4
✓ Branch 0 taken 5823401 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 20098 times.
✓ Branch 3 taken 5803307 times.
11646806 if (total_bytes > 0 &&
8776
2/2
✓ Branch 0 taken 5803304 times.
✓ Branch 1 taken 20097 times.
5823401 (m_binlog_file->get_real_file_size() >= (my_off_t)max_size ||
8777
3/4
✓ Branch 0 taken 5803304 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 5803303 times.
5803304 DBUG_EVALUATE_IF("simulate_max_binlog_size", true, false)))
8778 20098 *rotate_var = true;
8779 #ifndef NDEBUG
8780
5/8
✓ Branch 0 taken 5823405 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5823405 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 103 times.
✓ Branch 5 taken 5823302 times.
✓ Branch 6 taken 103 times.
✗ Branch 7 not taken.
5823405 DBUG_PRINT("info", ("no_flushes:= %d", no_flushes));
8781 5823405 no_flushes = 0;
8782 #endif
8783 5823405 return flush_error;
8784 5823405 }
8785
8786 /**
8787 Commit a sequence of sessions.
8788
8789 This function commit an entire queue of sessions starting with the
8790 session in @c first. If there were an error in the flushing part of
8791 the ordered commit, the error code is passed in and all the threads
8792 are marked accordingly (but not committed).
8793
8794 It will also add the GTIDs of the transactions to gtid_executed.
8795
8796 @see MYSQL_BIN_LOG::ordered_commit
8797
8798 @param thd The "master" thread
8799 @param first First thread in the queue of threads to commit
8800 */
8801
8802 5772700 void MYSQL_BIN_LOG::process_commit_stage_queue(THD *thd, THD *first) {
8803 5772700 mysql_mutex_assert_owner(&LOCK_commit);
8804 #ifndef NDEBUG
8805 5772700 thd->get_transaction()->m_flags.ready_preempt =
8806 true; // formality by the leader
8807 #endif
8808
2/2
✓ Branch 0 taken 5925658 times.
✓ Branch 1 taken 5772699 times.
11698357 for (THD *head = first; head; head = head->next_to_commit) {
8809
6/10
✓ Branch 0 taken 5925658 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5925658 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 98 times.
✓ Branch 5 taken 5925560 times.
✓ Branch 6 taken 98 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 98 times.
✗ Branch 9 not taken.
5925658 DBUG_PRINT("debug", ("Thread ID: %u, commit_error: %d, commit_pending: %s",
8810 head->thread_id(), head->commit_error,
8811 YESNO(head->tx_commit_pending)));
8812
2/8
✓ Branch 0 taken 5925658 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5925658 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
5925658 DBUG_EXECUTE_IF(
8813 "block_leader_after_delete",
8814 if (thd != head) { DBUG_SET("+d,after_delete_wait"); };);
8815 /*
8816 If flushing failed, set commit_error for the session, skip the
8817 transaction and proceed with the next transaction instead. This
8818 will mark all threads as failed, since the flush failed.
8819
8820 If flush succeeded, attach to the session and commit it in the
8821 engines.
8822 */
8823 #ifndef NDEBUG
8824
2/4
✓ Branch 0 taken 5925658 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5925658 times.
✗ Branch 3 not taken.
5925658 Commit_stage_manager::get_instance().clear_preempt_status(head);
8825 #endif
8826
2/2
✓ Branch 0 taken 5925657 times.
✓ Branch 1 taken 1 times.
5925658 if (head->get_transaction()->sequence_number != SEQ_UNINIT) {
8827
1/2
✓ Branch 0 taken 5925657 times.
✗ Branch 1 not taken.
5925657 mysql_mutex_lock(&LOCK_replica_trans_dep_tracker);
8828
1/2
✓ Branch 0 taken 5925657 times.
✗ Branch 1 not taken.
5925657 m_dependency_tracker.update_max_committed(head);
8829
1/2
✓ Branch 0 taken 5925657 times.
✗ Branch 1 not taken.
5925657 mysql_mutex_unlock(&LOCK_replica_trans_dep_tracker);
8830 }
8831 /*
8832 Flush/Sync error should be ignored and continue
8833 to commit phase. And thd->commit_error cannot be
8834 COMMIT_ERROR at this moment.
8835 */
8836
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5925658 times.
5925658 assert(head->commit_error != THD::CE_COMMIT_ERROR);
8837
1/2
✓ Branch 0 taken 5925658 times.
✗ Branch 1 not taken.
5925658 Thd_backup_and_restore switch_thd(thd, head);
8838 5925658 bool all = head->get_transaction()->m_flags.real_commit;
8839
3/4
✓ Branch 0 taken 5923835 times.
✓ Branch 1 taken 1823 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5923835 times.
5925658 assert(!head->get_transaction()->m_flags.commit_low ||
8840 head->get_transaction()->m_flags.ready_preempt);
8841
1/2
✓ Branch 0 taken 5925657 times.
✗ Branch 1 not taken.
5925658 ::finish_transaction_in_engines(head, all, false);
8842
6/10
✓ Branch 0 taken 5925657 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5925657 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 98 times.
✓ Branch 5 taken 5925559 times.
✓ Branch 6 taken 98 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 98 times.
✗ Branch 9 not taken.
5925657 DBUG_PRINT("debug", ("commit_error: %d, commit_pending: %s",
8843 head->commit_error, YESNO(head->tx_commit_pending)));
8844 5925657 }
8845
8846
2/2
✓ Branch 0 taken 5770049 times.
✓ Branch 1 taken 2650 times.
5772699 DEBUG_SYNC(thd, "process_commit_stage_queue_before_handle_gtid");
8847 /*
8848 Handle the GTID of the threads.
8849 gtid_executed table is kept updated even though transactions fail to be
8850 logged. That's required by slave auto positioning.
8851 */
8852 5772699 gtid_state->update_commit_group(first);
8853
8854
2/2
✓ Branch 0 taken 5925645 times.
✓ Branch 1 taken 5772687 times.
11698332 for (THD *head = first; head; head = head->next_to_commit) {
8855
1/2
✓ Branch 0 taken 5925645 times.
✗ Branch 1 not taken.
5925645 Thd_backup_and_restore switch_thd(thd, head);
8856 5925645 auto all = head->get_transaction()->m_flags.real_commit;
8857 // Mark transaction as prepared in TC, if applicable
8858
1/2
✓ Branch 0 taken 5925645 times.
✗ Branch 1 not taken.
5925645 trx_coordinator::set_prepared_in_tc_in_engines(head, all);
8859 /*
8860 Decrement the prepared XID counter after storage engine commit.
8861 We also need decrement the prepared XID when encountering a
8862 flush error or session attach error for avoiding 3-way deadlock
8863 among user thread, rotate thread and dump thread.
8864 */
8865
3/4
✓ Branch 0 taken 5384918 times.
✓ Branch 1 taken 540727 times.
✓ Branch 2 taken 5384918 times.
✗ Branch 3 not taken.
5925645 if (head->get_transaction()->m_flags.xid_written) dec_prep_xids(head);
8866 5925645 }
8867 5772687 }
8868
8869 /**
8870 Process after commit for a sequence of sessions.
8871
8872 @param thd The "master" thread
8873 @param first First thread in the queue of threads to commit
8874 */
8875
8876 5772685 void MYSQL_BIN_LOG::process_after_commit_stage_queue(THD *thd, THD *first) {
8877
2/2
✓ Branch 0 taken 5925644 times.
✓ Branch 1 taken 5772682 times.
11698326 for (THD *head = first; head; head = head->next_to_commit) {
8878
4/4
✓ Branch 0 taken 5923826 times.
✓ Branch 1 taken 1818 times.
✓ Branch 2 taken 5923826 times.
✓ Branch 3 taken 1818 times.
11849470 if (head->get_transaction()->m_flags.run_hooks &&
8879
1/2
✓ Branch 0 taken 5923826 times.
✗ Branch 1 not taken.
5923826 head->commit_error != THD::CE_COMMIT_ERROR) {
8880 /*
8881 TODO: This hook here should probably move outside/below this
8882 if and be the only after_commit invocation left in the
8883 code.
8884 */
8885
1/2
✓ Branch 0 taken 5923827 times.
✗ Branch 1 not taken.
5923826 Thd_backup_and_restore switch_thd(thd, head);
8886 5923827 bool all = head->get_transaction()->m_flags.real_commit;
8887
4/6
✓ Branch 0 taken 5923826 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 103057 times.
✓ Branch 3 taken 5820769 times.
✓ Branch 4 taken 103055 times.
✗ Branch 5 not taken.
5923827 (void)RUN_HOOK(transaction, after_commit, (head, all));
8888 /*
8889 When after_commit finished for the transaction, clear the run_hooks
8890 flag. This allow other parts of the system to check if after_commit was
8891 called.
8892 */
8893 5923824 head->get_transaction()->m_flags.run_hooks = false;
8894 5923826 }
8895 }
8896 5772682 }
8897
8898 #ifndef NDEBUG
8899 /** Names for the stages. */
8900 static const char *g_stage_name[] = {
8901 "FLUSH",
8902 "SYNC",
8903 "COMMIT",
8904 };
8905 #endif
8906
8907 17553496 bool MYSQL_BIN_LOG::change_stage(THD *thd [[maybe_unused]],
8908 Commit_stage_manager::StageID stage,
8909 THD *queue, mysql_mutex_t *leave_mutex,
8910 mysql_mutex_t *enter_mutex) {
8911
1/2
✓ Branch 0 taken 17553968 times.
✗ Branch 1 not taken.
17553496 DBUG_TRACE;
8912
5/8
✓ Branch 0 taken 17553739 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17553828 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 299 times.
✓ Branch 5 taken 17553529 times.
✓ Branch 6 taken 299 times.
✗ Branch 7 not taken.
17553968 DBUG_PRINT("enter", ("thd: 0x%llx, stage: %s, queue: 0x%llx", (ulonglong)thd,
8913 g_stage_name[stage], (ulonglong)queue));
8914
2/4
✓ Branch 0 taken 17553846 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17553850 times.
✗ Branch 3 not taken.
17553828 assert(0 <= stage && stage < Commit_stage_manager::STAGE_COUNTER);
8915
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17553850 times.
17553850 assert(enter_mutex);
8916
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17553850 times.
17553850 assert(queue);
8917 /*
8918 enroll_for will release the leave_mutex once the sessions are
8919 queued.
8920 */
8921
4/6
✓ Branch 0 taken 17553418 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17553530 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 152960 times.
✓ Branch 5 taken 17400570 times.
17553850 if (!Commit_stage_manager::get_instance().enroll_for(
8922 stage, queue, leave_mutex, enter_mutex)) {
8923
2/4
✓ Branch 0 taken 152959 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 152957 times.
152960 assert(!thd_get_cache_mngr(thd)->dbug_any_finalized());
8924 152957 return true;
8925 }
8926
8927 17400570 return false;
8928 17553527 }
8929
8930 /**
8931 Flush the I/O cache to file.
8932
8933 Flush the binary log to the binlog file if any byte where written
8934 and signal that the binary log file has been updated if the flush
8935 succeeds.
8936 */
8937
8938 5823401 int MYSQL_BIN_LOG::flush_cache_to_file(my_off_t *end_pos_var) {
8939
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 5823399 times.
5823401 if (m_binlog_file->flush()) {
8940 2 THD *thd = current_thd;
8941 2 thd->commit_error = THD::CE_FLUSH_ERROR;
8942 2 return ER_ERROR_ON_WRITE;
8943 }
8944 5823399 *end_pos_var = m_binlog_file->position();
8945 5823399 return 0;
8946 }
8947
8948 /**
8949 Call fsync() to sync the file to disk.
8950 */
8951 7580711 std::pair<bool, bool> MYSQL_BIN_LOG::sync_binlog_file(bool force) {
8952 7580711 bool synced = false;
8953 7580711 unsigned int sync_period = get_sync_period();
8954
8/8
✓ Branch 0 taken 7572144 times.
✓ Branch 1 taken 8571 times.
✓ Branch 2 taken 7496988 times.
✓ Branch 3 taken 75156 times.
✓ Branch 4 taken 5728598 times.
✓ Branch 5 taken 1768390 times.
✓ Branch 6 taken 5737169 times.
✓ Branch 7 taken 1843546 times.
7580715 if (force || (sync_period && ++sync_counter >= sync_period)) {
8955 5737169 sync_counter = 0;
8956
8957 /*
8958 There is a chance that binlog file could be closed by 'RESET MASTER' or
8959 or 'FLUSH LOGS' just after the leader releases LOCK_log and before it
8960 acquires LOCK_sync log. So it should check if m_binlog_file is opened.
8961 */
8962
9/12
✓ Branch 0 taken 5737169 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5737165 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 5737164 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 5737164 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 5737164 times.
✓ Branch 10 taken 4 times.
✓ Branch 11 taken 5737165 times.
5737169 if (DBUG_EVALUATE_IF("simulate_error_during_sync_binlog_file", 1,
8963 m_binlog_file->is_open() && m_binlog_file->sync())) {
8964
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 THD *thd = current_thd;
8965 4 thd->commit_error = THD::CE_SYNC_ERROR;
8966
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 return std::make_pair(true, synced);
8967 }
8968 5737165 synced = true;
8969 }
8970
1/2
✓ Branch 0 taken 7580712 times.
✗ Branch 1 not taken.
7580711 return std::make_pair(false, synced);
8971 }
8972
8973 /**
8974 Helper function executed when leaving @c ordered_commit.
8975
8976 This function contain the necessary code for fetching the error
8977 code, doing post-commit checks, and wrapping up the commit if
8978 necessary.
8979
8980 It is typically called when enter_stage indicates that the thread
8981 should bail out, and also when the ultimate leader thread finishes
8982 executing @c ordered_commit.
8983
8984 It is typically used in this manner:
8985 @code
8986 if (enter_stage(thd, Thread_queue::BINLOG_FLUSH_STAGE, thd, &LOCK_log))
8987 return finish_commit(thd);
8988 @endcode
8989
8990 @return Error code if the session commit failed, or zero on
8991 success.
8992 */
8993 5926245 int MYSQL_BIN_LOG::finish_commit(THD *thd) {
8994
1/2
✓ Branch 0 taken 5926264 times.
✗ Branch 1 not taken.
5926245 DBUG_TRACE;
8995
3/4
✓ Branch 0 taken 5923602 times.
✓ Branch 1 taken 2662 times.
✓ Branch 2 taken 5923613 times.
✗ Branch 3 not taken.
5926264 DEBUG_SYNC(thd, "reached_finish_commit");
8996 /*
8997 In some unlikely situations, it can happen that binary
8998 log is closed before the thread flushes it's cache.
8999 In that case, clear the caches before doing commit.
9000 */
9001
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 5926237 times.
5926275 if (unlikely(!is_open())) {
9002
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 binlog_cache_mngr *cache_mngr = thd_get_cache_mngr(thd);
9003
2/4
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
15 if (cache_mngr) cache_mngr->reset();
9004 }
9005
9006
2/2
✓ Branch 0 taken 624 times.
✓ Branch 1 taken 5925611 times.
5926252 if (thd->get_transaction()->sequence_number != SEQ_UNINIT) {
9007
1/2
✓ Branch 0 taken 624 times.
✗ Branch 1 not taken.
624 mysql_mutex_lock(&LOCK_replica_trans_dep_tracker);
9008
1/2
✓ Branch 0 taken 624 times.
✗ Branch 1 not taken.
624 m_dependency_tracker.update_max_committed(thd);
9009
1/2
✓ Branch 0 taken 624 times.
✗ Branch 1 not taken.
624 mysql_mutex_unlock(&LOCK_replica_trans_dep_tracker);
9010 }
9011
9012 5926235 auto all = thd->get_transaction()->m_flags.real_commit;
9013 5926235 auto committed_low = thd->get_transaction()->m_flags.commit_low;
9014
9015
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5926266 times.
5926266 assert(thd->commit_error != THD::CE_COMMIT_ERROR);
9016
1/2
✓ Branch 0 taken 5926241 times.
✗ Branch 1 not taken.
5926266 ::finish_transaction_in_engines(thd, all, false);
9017
9018 // If the ordered commit didn't updated the GTIDs for this thd yet
9019 // at process_commit_stage_queue (i.e. --binlog-order-commits=0)
9020 // the thd still has the ownership of a GTID and we must handle it.
9021
3/4
✓ Branch 0 taken 5926194 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1314 times.
✓ Branch 3 taken 5924880 times.
5926241 if (!thd->owned_gtid_is_empty()) {
9022
1/2
✓ Branch 0 taken 1314 times.
✗ Branch 1 not taken.
1314 if (thd->commit_error == THD::CE_NONE) {
9023
1/2
✓ Branch 0 taken 1314 times.
✗ Branch 1 not taken.
1314 gtid_state->update_on_commit(thd);
9024 } else
9025 gtid_state->update_on_rollback(thd);
9026 }
9027
9028 // If not yet done, mark transaction as prepared in TC, if applicable and
9029 // unfence the rotation of the binary log
9030
2/2
✓ Branch 0 taken 624 times.
✓ Branch 1 taken 5925574 times.
5926194 if (thd->get_transaction()->m_flags.xid_written) {
9031
1/2
✓ Branch 0 taken 624 times.
✗ Branch 1 not taken.
624 trx_coordinator::set_prepared_in_tc_in_engines(thd, all);
9032
1/2
✓ Branch 0 taken 611 times.
✗ Branch 1 not taken.
624 dec_prep_xids(thd);
9033 }
9034
9035 // If the transaction was committed successfully, run the after_commit
9036
5/6
✓ Branch 0 taken 1024 times.
✓ Branch 1 taken 5925161 times.
✓ Branch 2 taken 1024 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 624 times.
✓ Branch 5 taken 5925561 times.
5927209 if (committed_low && (thd->commit_error != THD::CE_COMMIT_ERROR) &&
9037
2/2
✓ Branch 0 taken 624 times.
✓ Branch 1 taken 400 times.
1024 thd->get_transaction()->m_flags.run_hooks) {
9038
4/6
✓ Branch 0 taken 624 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 606 times.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
624 (void)RUN_HOOK(transaction, after_commit, (thd, all));
9039 624 thd->get_transaction()->m_flags.run_hooks = false;
9040 }
9041
9042
2/10
✓ Branch 0 taken 5926175 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5926175 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
5926185 DBUG_EXECUTE_IF("leaving_finish_commit", {
9043 const char act[] = "now SIGNAL signal_leaving_finish_commit";
9044 assert(!debug_sync_set_action(current_thd, STRING_WITH_LEN(act)));
9045 };);
9046
9047
3/4
✓ Branch 0 taken 5916279 times.
✓ Branch 1 taken 9896 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5916281 times.
5926175 assert(thd->commit_error || !thd->get_transaction()->m_flags.run_hooks);
9048
2/4
✓ Branch 0 taken 5926238 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5926232 times.
5926177 assert(!thd_get_cache_mngr(thd)->dbug_any_finalized());
9049
5/8
✓ Branch 0 taken 5926177 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5926179 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 98 times.
✓ Branch 5 taken 5926081 times.
✓ Branch 6 taken 98 times.
✗ Branch 7 not taken.
5926232 DBUG_PRINT("return", ("Thread ID: %u, commit_error: %d", thd->thread_id(),
9050 thd->commit_error));
9051 /*
9052 flush or sync errors are handled by the leader of the group
9053 (using binlog_error_action). Hence treat only COMMIT_ERRORs as errors.
9054 */
9055 5926225 return thd->commit_error == THD::CE_COMMIT_ERROR;
9056 5926179 }
9057
9058 /**
9059 Auxiliary function used in ordered_commit.
9060 */
9061 5773311 static inline int call_after_sync_hook(THD *queue_head) {
9062 5773311 const char *log_file = nullptr;
9063 5773311 my_off_t pos = 0;
9064
9065
3/4
✓ Branch 0 taken 5773311 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5747159 times.
✓ Branch 3 taken 26152 times.
5773311 if (NO_HOOK(binlog_storage)) return 0;
9066
9067
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26152 times.
26152 assert(queue_head != nullptr);
9068
2/2
✓ Branch 0 taken 63548 times.
✓ Branch 1 taken 26152 times.
89700 for (THD *thd = queue_head; thd != nullptr; thd = thd->next_to_commit)
9069
1/2
✓ Branch 0 taken 63548 times.
✗ Branch 1 not taken.
63548 if (likely(thd->commit_error == THD::CE_NONE))
9070
1/2
✓ Branch 0 taken 63548 times.
✗ Branch 1 not taken.
63548 thd->get_trans_fixed_pos(&log_file, &pos);
9071
9072
6/8
✓ Branch 0 taken 26152 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 26149 times.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 26149 times.
✓ Branch 6 taken 3 times.
✓ Branch 7 taken 26149 times.
52301 if (DBUG_EVALUATE_IF("simulate_after_sync_hook_error", 1, 0) ||
9073
3/6
✓ Branch 0 taken 26149 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 26149 times.
✓ Branch 4 taken 26149 times.
✗ Branch 5 not taken.
26149 RUN_HOOK(binlog_storage, after_sync, (queue_head, log_file, pos))) {
9074
8/16
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 3 times.
✗ Branch 15 not taken.
3 LogErr(ERROR_LEVEL, ER_BINLOG_FAILED_TO_RUN_AFTER_SYNC_HOOK);
9075 3 return ER_ERROR_ON_WRITE;
9076 }
9077 26149 return 0;
9078 }
9079
9080 /**
9081 Helper function to handle flush or sync stage errors.
9082 If binlog_error_action= ABORT_SERVER, server will be aborted
9083 after reporting the error to the client.
9084 If binlog_error_action= IGNORE_ERROR, binlog will be closed
9085 for the reset of the life time of the server. close() call is protected
9086 with LOCK_log to avoid any parallel operations on binary log.
9087
9088 @param thd Thread object that faced flush/sync error
9089 @param need_lock_log
9090 > Indicates true if LOCk_log is needed before closing
9091 binlog (happens when we are handling sync error)
9092 > Indicates false if LOCK_log is already acquired
9093 by the thread (happens when we are handling flush
9094 error)
9095 @param message Message stating the reason of the failure
9096 */
9097 14 void MYSQL_BIN_LOG::handle_binlog_flush_or_sync_error(THD *thd,
9098 bool need_lock_log,
9099 const char *message) {
9100 14 char errmsg[MYSQL_ERRMSG_SIZE] = {0};
9101
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 2 times.
14 if (message == nullptr)
9102 24 sprintf(
9103 errmsg,
9104 "An error occurred during %s stage of the commit. "
9105 "'binlog_error_action' is set to '%s'.",
9106
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 7 times.
12 thd->commit_error == THD::CE_FLUSH_ERROR ? "flush" : "sync",
9107
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 binlog_error_action == ABORT_SERVER ? "ABORT_SERVER" : "IGNORE_ERROR");
9108 else
9109 2 strncpy(errmsg, message, MYSQL_ERRMSG_SIZE - 1);
9110
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 if (binlog_error_action == ABORT_SERVER) {
9111 char err_buff[MYSQL_ERRMSG_SIZE + 25];
9112 sprintf(err_buff, "%s Server is being stopped.", errmsg);
9113 exec_binlog_error_action_abort(err_buff);
9114 } else {
9115
2/4
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
14 DEBUG_SYNC(thd, "before_binlog_closed_due_to_error");
9116
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 6 times.
14 if (need_lock_log)
9117
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 mysql_mutex_lock(&LOCK_log);
9118 else
9119 6 mysql_mutex_assert_owner(&LOCK_log);
9120 /*
9121 It can happen that other group leader encountered
9122 error and already closed the binary log. So print
9123 error only if it is in open state. But we should
9124 call close() always just in case if the previous
9125 close did not close index file.
9126 */
9127
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1 times.
14 if (is_open()) {
9128
8/16
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 13 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 13 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 13 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 13 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 13 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 13 times.
✗ Branch 15 not taken.
13 LogErr(ERROR_LEVEL, ER_TURNING_LOGGING_OFF_FOR_THE_DURATION, errmsg);
9129 }
9130
1/2
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
14 close(LOG_CLOSE_INDEX | LOG_CLOSE_STOP_EVENT, false /*need_lock_log=false*/,
9131 true /*need_lock_index=true*/);
9132 /*
9133 If there is a write error (flush/sync stage) and if
9134 binlog_error_action=IGNORE_ERROR, clear the error
9135 and allow the commit to happen in storage engine.
9136 */
9137
5/6
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 11 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 12 times.
17 if (check_write_error(thd) &&
9138
3/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 1 times.
3 DBUG_EVALUATE_IF("simulate_cache_creation_failure", false, true)) {
9139 /* we have DA_ERROR */
9140
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 thd->clear_error(); /* sets thd->get_stmt_da()->status() to DA_EMPTY */
9141 /* For SQLCOM_COMMIT, ROLLBACK, ROLLBACK TO SAVEPOINT, there is already
9142 my_ok() in mysql_execute_command. Doing double my_ok() is not allowed. So
9143 we avoid that here */
9144
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (thd_sql_command(thd) != SQLCOM_COMMIT &&
9145
6/8
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 1 times.
3 thd_sql_command(thd) != SQLCOM_ROLLBACK &&
9146
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 thd_sql_command(thd) != SQLCOM_ROLLBACK_TO_SAVEPOINT) {
9147
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 my_ok(thd); /* sets thd->get_stmt_da()->status() to DA_OK */
9148 }
9149 }
9150
9151
3/4
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
14 if (need_lock_log) mysql_mutex_unlock(&LOCK_log);
9152
2/4
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
14 DEBUG_SYNC(thd, "after_binlog_closed_due_to_error");
9153 }
9154 14 }
9155
9156 5925928 int MYSQL_BIN_LOG::ordered_commit(THD *thd, bool all, bool skip_commit) {
9157
1/2
✓ Branch 0 taken 5926364 times.
✗ Branch 1 not taken.
5925928 DBUG_TRACE;
9158 5926364 int flush_error = 0, sync_error = 0;
9159 5926364 my_off_t total_bytes = 0;
9160 5926364 bool do_rotate = false;
9161
9162
4/6
✓ Branch 0 taken 5926167 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 90 times.
✓ Branch 3 taken 5926077 times.
✓ Branch 4 taken 90 times.
✗ Branch 5 not taken.
5926364 DBUG_EXECUTE_IF("crash_commit_before_log", DBUG_SUICIDE(););
9163
1/2
✓ Branch 0 taken 5926393 times.
✗ Branch 1 not taken.
5926077 init_thd_variables(thd, all, skip_commit);
9164
6/10
✓ Branch 0 taken 5926050 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5926126 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 103 times.
✓ Branch 5 taken 5926023 times.
✓ Branch 6 taken 103 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 103 times.
✗ Branch 9 not taken.
5926393 DBUG_PRINT("enter", ("commit_pending: %s, commit_error: %d, thread_id: %u",
9165 YESNO(thd->tx_commit_pending), thd->commit_error,
9166 thd->thread_id()));
9167
9168
3/4
✓ Branch 0 taken 5923259 times.
✓ Branch 1 taken 2633 times.
✓ Branch 2 taken 5923625 times.
✗ Branch 3 not taken.
5926126 DEBUG_SYNC(thd, "bgc_before_flush_stage");
9169
9170 /*
9171 Stage #0: ensure slave threads commit order as they appear in the slave's
9172 relay log for transactions flushing to binary log.
9173
9174 This will make thread wait until its turn to commit.
9175 Commit_order_manager maintains it own queue and its own order for the
9176 commit. So Stage#0 doesn't maintain separate StageID.
9177 */
9178
1/2
✓ Branch 0 taken 5925950 times.
✗ Branch 1 not taken.
5926258 if (Commit_order_manager::wait_for_its_turn_before_flush_stage(thd) ||
9179
7/8
✓ Branch 0 taken 5907773 times.
✓ Branch 1 taken 18177 times.
✓ Branch 2 taken 5907919 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 197751 times.
✓ Branch 5 taken 5710168 times.
✓ Branch 6 taken 5728499 times.
✓ Branch 7 taken 197615 times.
6123719 ending_trans(thd, all) ||
9180
2/4
✓ Branch 0 taken 197769 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 197769 times.
197751 Commit_order_manager::get_rollback_status(thd)) {
9181
3/4
✓ Branch 0 taken 5728491 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 71 times.
✓ Branch 3 taken 5728420 times.
5728499 if (Commit_order_manager::wait(thd)) {
9182 71 return thd->commit_error;
9183 }
9184 }
9185
9186 /*
9187 Stage #1: flushing transactions to binary log
9188
9189 While flushing, we allow new threads to enter and will process
9190 them in due time. Once the queue was empty, we cannot reap
9191 anything more since it is possible that a thread entered and
9192 appointed itself leader for the flush phase.
9193 */
9194
9195
3/4
✓ Branch 0 taken 5926410 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 103007 times.
✓ Branch 3 taken 5823403 times.
5926035 if (change_stage(thd, Commit_stage_manager::BINLOG_FLUSH_STAGE, thd, nullptr,
9196 &LOCK_log)) {
9197
3/8
✓ Branch 0 taken 103006 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 103006 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 103006 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
103007 DBUG_PRINT("return", ("Thread ID: %u, commit_error: %d", thd->thread_id(),
9198 thd->commit_error));
9199
1/2
✓ Branch 0 taken 102985 times.
✗ Branch 1 not taken.
103006 return finish_commit(thd);
9200 }
9201
9202 5823403 THD *wait_queue = nullptr, *final_queue = nullptr;
9203 5823403 mysql_mutex_t *leave_mutex_before_commit_stage = nullptr;
9204 5823403 my_off_t flush_end_pos = 0;
9205 bool update_binlog_end_pos_after_sync;
9206
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 5823419 times.
5823403 if (unlikely(!is_open())) {
9207
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 final_queue = fetch_and_process_flush_stage_queue(true);
9208 1 leave_mutex_before_commit_stage = &LOCK_log;
9209 /*
9210 binary log is closed, flush stage and sync stage should be
9211 ignored. Binlog cache should be cleared, but instead of doing
9212 it here, do that work in 'finish_commit' function so that
9213 leader and followers thread caches will be cleared.
9214 */
9215 1 goto commit_stage;
9216 }
9217
3/4
✓ Branch 0 taken 5820769 times.
✓ Branch 1 taken 2650 times.
✓ Branch 2 taken 5820769 times.
✗ Branch 3 not taken.
5823419 DEBUG_SYNC(thd, "waiting_in_the_middle_of_flush_stage");
9218 flush_error =
9219
1/2
✓ Branch 0 taken 5823405 times.
✗ Branch 1 not taken.
5823419 process_flush_stage_queue(&total_bytes, &do_rotate, &wait_queue);
9220
9221
3/4
✓ Branch 0 taken 5823401 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 5823401 times.
✗ Branch 3 not taken.
5823405 if (flush_error == 0 && total_bytes > 0)
9222
1/2
✓ Branch 0 taken 5823401 times.
✗ Branch 1 not taken.
5823401 flush_error = flush_cache_to_file(&flush_end_pos);
9223
4/6
✓ Branch 0 taken 5823405 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 5823401 times.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
5823405 DBUG_EXECUTE_IF("crash_after_flush_binlog", DBUG_SUICIDE(););
9224
9225 5823401 update_binlog_end_pos_after_sync = (get_sync_period() == 1);
9226
9227 /*
9228 If the flush finished successfully, we can call the after_flush
9229 hook. Being invoked here, we have the guarantee that the hook is
9230 executed before the before/after_send_hooks on the dump thread
9231 preventing race conditions among these plug-ins.
9232 */
9233
2/2
✓ Branch 0 taken 5823395 times.
✓ Branch 1 taken 6 times.
5823401 if (flush_error == 0) {
9234
1/2
✓ Branch 0 taken 5823395 times.
✗ Branch 1 not taken.
5823395 const char *file_name_ptr = log_file_name + dirname_length(log_file_name);
9235
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5823395 times.
5823395 assert(flush_end_pos != 0);
9236
5/8
✓ Branch 0 taken 5823395 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5785360 times.
✓ Branch 3 taken 38035 times.
✓ Branch 4 taken 38035 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 5823395 times.
5823395 if (RUN_HOOK(binlog_storage, after_flush,
9237 (thd, file_name_ptr, flush_end_pos))) {
9238 LogErr(ERROR_LEVEL, ER_BINLOG_FAILED_TO_RUN_AFTER_FLUSH_HOOK);
9239 flush_error = ER_ERROR_ON_WRITE;
9240 }
9241
9242
3/4
✓ Branch 0 taken 77013 times.
✓ Branch 1 taken 5746382 times.
✓ Branch 2 taken 77013 times.
✗ Branch 3 not taken.
5823395 if (!update_binlog_end_pos_after_sync) update_binlog_end_pos();
9243
9244
4/6
✓ Branch 0 taken 5823395 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 129 times.
✓ Branch 3 taken 5823266 times.
✓ Branch 4 taken 129 times.
✗ Branch 5 not taken.
5823395 DBUG_EXECUTE_IF("crash_commit_after_log", DBUG_SUICIDE(););
9245 }
9246
9247
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 5823266 times.
5823272 if (flush_error) {
9248 /*
9249 Handle flush error (if any) after leader finishes it's flush stage.
9250 */
9251
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 handle_binlog_flush_or_sync_error(
9252 thd, false /* need_lock_log */,
9253
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 5 times.
6 (thd->commit_error == THD::CE_FLUSH_GNO_EXHAUSTED_ERROR)
9254
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 ? ER_THD(thd, ER_GNO_EXHAUSTED)
9255 : nullptr);
9256 }
9257
9258
1/2
✓ Branch 0 taken 5823272 times.
✗ Branch 1 not taken.
5823272 publish_coordinates_for_global_status();
9259
9260
3/4
✓ Branch 0 taken 5820622 times.
✓ Branch 1 taken 2650 times.
✓ Branch 2 taken 5820622 times.
✗ Branch 3 not taken.
5823272 DEBUG_SYNC(thd, "bgc_after_flush_stage_before_sync_stage");
9261
9262 /*
9263 Stage #2: Syncing binary log file to disk
9264 */
9265
9266
3/4
✓ Branch 0 taken 5823270 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18175 times.
✓ Branch 3 taken 5805095 times.
5823272 if (change_stage(thd, Commit_stage_manager::SYNC_STAGE, wait_queue, &LOCK_log,
9267 &LOCK_sync)) {
9268
3/8
✓ Branch 0 taken 18175 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18175 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 18175 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
18175 DBUG_PRINT("return", ("Thread ID: %u, commit_error: %d", thd->thread_id(),
9269 thd->commit_error));
9270
1/2
✓ Branch 0 taken 18173 times.
✗ Branch 1 not taken.
18175 return finish_commit(thd);
9271 }
9272
9273 /*
9274 Shall introduce a delay only if it is going to do sync
9275 in this ongoing SYNC stage. The "+1" used below in the
9276 if condition is to count the ongoing sync stage.
9277 When sync_binlog=0 (where we never do sync in BGC group),
9278 it is considered as a special case and delay will be executed
9279 for every group just like how it is done when sync_binlog= 1.
9280 */
9281
6/6
✓ Branch 0 taken 5805091 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 5803657 times.
✓ Branch 3 taken 1434 times.
✓ Branch 4 taken 5803657 times.
✓ Branch 5 taken 1438 times.
5805095 if (!flush_error && (sync_counter + 1 >= get_sync_period()))
9282
2/4
✓ Branch 0 taken 5803657 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5803657 times.
✗ Branch 3 not taken.
5803657 Commit_stage_manager::get_instance().wait_count_or_timeout(
9283 opt_binlog_group_commit_sync_no_delay_count,
9284 opt_binlog_group_commit_sync_delay, Commit_stage_manager::SYNC_STAGE);
9285
9286
2/4
✓ Branch 0 taken 5805097 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5805097 times.
✗ Branch 3 not taken.
5805095 final_queue = Commit_stage_manager::get_instance().fetch_queue_acquire_lock(
9287 Commit_stage_manager::SYNC_STAGE);
9288
9289
3/4
✓ Branch 0 taken 5805091 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 5805091 times.
✗ Branch 3 not taken.
5805097 if (flush_error == 0 && total_bytes > 0) {
9290
3/4
✓ Branch 0 taken 5802441 times.
✓ Branch 1 taken 2650 times.
✓ Branch 2 taken 5802441 times.
✗ Branch 3 not taken.
5805091 DEBUG_SYNC(thd, "before_sync_binlog_file");
9291
1/2
✓ Branch 0 taken 5805091 times.
✗ Branch 1 not taken.
5805091 std::pair<bool, bool> result = sync_binlog_file(false);
9292 5805091 sync_error = result.first;
9293 }
9294
9295
2/2
✓ Branch 0 taken 5728506 times.
✓ Branch 1 taken 76591 times.
5805097 if (update_binlog_end_pos_after_sync) {
9296 5728506 THD *tmp_thd = final_queue;
9297 5728506 const char *binlog_file = nullptr;
9298 5728506 my_off_t pos = 0;
9299
2/2
✓ Branch 0 taken 81601 times.
✓ Branch 1 taken 5728506 times.
5810107 while (tmp_thd->next_to_commit != nullptr)
9300 81601 tmp_thd = tmp_thd->next_to_commit;
9301
4/4
✓ Branch 0 taken 5728500 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 5728496 times.
✓ Branch 3 taken 4 times.
5728506 if (flush_error == 0 && sync_error == 0) {
9302
1/2
✓ Branch 0 taken 5728496 times.
✗ Branch 1 not taken.
5728496 tmp_thd->get_trans_fixed_pos(&binlog_file, &pos);
9303
1/2
✓ Branch 0 taken 5728496 times.
✗ Branch 1 not taken.
5728496 update_binlog_end_pos(binlog_file, pos);
9304 }
9305 }
9306
9307
3/4
✓ Branch 0 taken 5802447 times.
✓ Branch 1 taken 2650 times.
✓ Branch 2 taken 5802447 times.
✗ Branch 3 not taken.
5805097 DEBUG_SYNC(thd, "bgc_after_sync_stage_before_commit_stage");
9308
9309 5805097 leave_mutex_before_commit_stage = &LOCK_sync;
9310 /*
9311 Stage #3: Commit all transactions in order.
9312
9313 This stage is skipped if we do not need to order the commits and
9314 each thread have to execute the handlerton commit instead.
9315
9316 However, since we are keeping the lock from the previous stage, we
9317 need to unlock it if we skip the stage.
9318
9319 We must also step commit_clock before the ha_commit_low() is called
9320 either in ordered fashion (by the leader of this stage) or by the thread
9321 themselves.
9322
9323 We are delaying the handling of sync error until
9324 all locks are released but we should not enter into
9325 commit stage if binlog_error_action is ABORT_SERVER.
9326 */
9327 5805098 commit_stage:
9328 /* Clone needs binlog commit order. */
9329
7/8
✓ Branch 0 taken 621 times.
✓ Branch 1 taken 5804477 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 621 times.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 5804473 times.
✓ Branch 6 taken 5804477 times.
✓ Branch 7 taken 621 times.
5805102 if ((opt_binlog_order_commits || Clone_handler::need_commit_order()) &&
9330
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 (sync_error == 0 || binlog_error_action != ABORT_SERVER)) {
9331
3/4
✓ Branch 0 taken 5804468 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 31777 times.
✓ Branch 3 taken 5772691 times.
5804477 if (change_stage(thd, Commit_stage_manager::COMMIT_STAGE, final_queue,
9332 leave_mutex_before_commit_stage, &LOCK_commit)) {
9333
3/8
✓ Branch 0 taken 31777 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 31777 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 31777 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
31777 DBUG_PRINT("return", ("Thread ID: %u, commit_error: %d", thd->thread_id(),
9334 thd->commit_error));
9335
1/2
✓ Branch 0 taken 31765 times.
✗ Branch 1 not taken.
31777 return finish_commit(thd);
9336 }
9337 THD *commit_queue =
9338
2/4
✓ Branch 0 taken 5772700 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5772700 times.
✗ Branch 3 not taken.
5772691 Commit_stage_manager::get_instance().fetch_queue_acquire_lock(
9339 Commit_stage_manager::COMMIT_STAGE);
9340
5/8
✓ Branch 0 taken 5772700 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 200 times.
✓ Branch 3 taken 5772500 times.
✓ Branch 4 taken 200 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 200 times.
✗ Branch 7 not taken.
5772700 DBUG_EXECUTE_IF("semi_sync_3-way_deadlock",
9341 DEBUG_SYNC(thd, "before_process_commit_stage_queue"););
9342
9343
4/4
✓ Branch 0 taken 5772694 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 5772690 times.
✓ Branch 3 taken 4 times.
5772700 if (flush_error == 0 && sync_error == 0)
9344
1/2
✓ Branch 0 taken 5772690 times.
✗ Branch 1 not taken.
5772690 sync_error = call_after_sync_hook(commit_queue);
9345
9346 /*
9347 process_commit_stage_queue will call update_on_commit or
9348 update_on_rollback for the GTID owned by each thd in the queue.
9349
9350 This will be done this way to guarantee that GTIDs are added to
9351 gtid_executed in order, to avoid creating unnecessary temporary
9352 gaps and keep gtid_executed as a single interval at all times.
9353
9354 If we allow each thread to call update_on_commit only when they
9355 are at finish_commit, the GTID order cannot be guaranteed and
9356 temporary gaps may appear in gtid_executed. When this happen,
9357 the server would have to add and remove intervals from the
9358 Gtid_set, and adding and removing intervals requires a mutex,
9359 which would reduce performance.
9360 */
9361
1/2
✓ Branch 0 taken 5772687 times.
✗ Branch 1 not taken.
5772700 process_commit_stage_queue(thd, commit_queue);
9362
1/2
✓ Branch 0 taken 5772686 times.
✗ Branch 1 not taken.
5772687 mysql_mutex_unlock(&LOCK_commit);
9363 /*
9364 Process after_commit after LOCK_commit is released for avoiding
9365 3-way deadlock among user thread, rotate thread and dump thread.
9366 */
9367
1/2
✓ Branch 0 taken 5772683 times.
✗ Branch 1 not taken.
5772686 process_after_commit_stage_queue(thd, commit_queue);
9368 5772683 final_queue = commit_queue;
9369 } else {
9370
1/2
✓ Branch 0 taken 621 times.
✗ Branch 1 not taken.
621 if (leave_mutex_before_commit_stage)
9371
1/2
✓ Branch 0 taken 621 times.
✗ Branch 1 not taken.
621 mysql_mutex_unlock(leave_mutex_before_commit_stage);
9372
2/4
✓ Branch 0 taken 621 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 621 times.
✗ Branch 3 not taken.
621 if (flush_error == 0 && sync_error == 0)
9373
1/2
✓ Branch 0 taken 621 times.
✗ Branch 1 not taken.
621 sync_error = call_after_sync_hook(final_queue);
9374 }
9375
9376 /*
9377 Handle sync error after we release all locks in order to avoid deadlocks
9378 */
9379
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 5773297 times.
5773304 if (sync_error)
9380
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 handle_binlog_flush_or_sync_error(thd, true /* need_lock_log */, nullptr);
9381
9382
3/4
✓ Branch 0 taken 5770655 times.
✓ Branch 1 taken 2650 times.
✓ Branch 2 taken 5770658 times.
✗ Branch 3 not taken.
5773304 DEBUG_SYNC(thd, "before_signal_done");
9383 /* Commit done so signal all waiting threads */
9384
2/4
✓ Branch 0 taken 5773306 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5773308 times.
✗ Branch 3 not taken.
5773308 Commit_stage_manager::get_instance().signal_done(final_queue);
9385
2/8
✓ Branch 0 taken 5773308 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5773308 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
5773308 DBUG_EXECUTE_IF("block_leader_after_delete", {
9386 const char action[] = "now SIGNAL leader_proceed";
9387 assert(!debug_sync_set_action(thd, STRING_WITH_LEN(action)));
9388 };);
9389
9390 /*
9391 Finish the commit before executing a rotate, or run the risk of a
9392 deadlock. We don't need the return value here since it is in
9393 thd->commit_error, which is returned below.
9394 */
9395
1/2
✓ Branch 0 taken 5773301 times.
✗ Branch 1 not taken.
5773308 (void)finish_commit(thd);
9396
3/4
✓ Branch 0 taken 5770653 times.
✓ Branch 1 taken 2651 times.
✓ Branch 2 taken 5770658 times.
✗ Branch 3 not taken.
5773301 DEBUG_SYNC(thd, "bgc_after_commit_stage_before_rotation");
9397
9398 /*
9399 If we need to rotate, we do it without commit error.
9400 Otherwise the thd->commit_error will be possibly reset.
9401 */
9402
7/8
✓ Branch 0 taken 5773307 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5773303 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 13410 times.
✓ Branch 5 taken 5759893 times.
✓ Branch 6 taken 12248 times.
✓ Branch 7 taken 5761059 times.
5786719 if (DBUG_EVALUATE_IF("force_rotate", 1, 0) ||
9403
2/2
✓ Branch 0 taken 12244 times.
✓ Branch 1 taken 1166 times.
13410 (do_rotate && thd->commit_error == THD::CE_NONE &&
9404
1/2
✓ Branch 0 taken 12244 times.
✗ Branch 1 not taken.
12244 !is_rotating_caused_by_incident)) {
9405 /*
9406 Do not force the rotate as several consecutive groups may
9407 request unnecessary rotations.
9408
9409 NOTE: Run purge_logs wo/ holding LOCK_log because it does not
9410 need the mutex. Otherwise causes various deadlocks.
9411 */
9412
9413
2/4
✓ Branch 0 taken 12247 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12248 times.
✗ Branch 3 not taken.
12248 DEBUG_SYNC(thd, "ready_to_do_rotation");
9414 12248 bool check_purge = false;
9415
1/2
✓ Branch 0 taken 12249 times.
✗ Branch 1 not taken.
12248 mysql_mutex_lock(&LOCK_log);
9416 /*
9417 If rotate fails then depends on binlog_error_action variable
9418 appropriate action will be taken inside rotate call.
9419 */
9420
1/2
✓ Branch 0 taken 12249 times.
✗ Branch 1 not taken.
12249 int error = rotate(false, &check_purge);
9421
1/2
✓ Branch 0 taken 12249 times.
✗ Branch 1 not taken.
12249 mysql_mutex_unlock(&LOCK_log);
9422
9423
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 12238 times.
12249 if (error)
9424 11 thd->commit_error = THD::CE_COMMIT_ERROR;
9425
2/2
✓ Branch 0 taken 6944 times.
✓ Branch 1 taken 5294 times.
12238 else if (check_purge)
9426
1/2
✓ Branch 0 taken 6944 times.
✗ Branch 1 not taken.
6944 auto_purge();
9427 }
9428
9429
6/6
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 5773280 times.
✓ Branch 2 taken 25 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 18 times.
✓ Branch 5 taken 5773290 times.
5773333 if (binlog_space_limit && binlog_space_total &&
9430
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 7 times.
25 binlog_space_total + m_binlog_file->position() > binlog_space_limit)
9431
1/2
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
18 purge_logs_by_size(true);
9432
9433 /*
9434 flush or sync errors are handled above (using binlog_error_action).
9435 Hence treat only COMMIT_ERRORs as errors.
9436 */
9437 5773303 return thd->commit_error == THD::CE_COMMIT_ERROR;
9438 5926297 }
9439
9440 /** Copy the current binlog coordinates to the variables used for the
9441 not-in-consistent-snapshot case of SHOW STATUS */
9442 5832998 void MYSQL_BIN_LOG::publish_coordinates_for_global_status(void) const {
9443 5832998 mysql_mutex_assert_owner(&LOCK_log);
9444
9445 5832998 mysql_mutex_lock(&LOCK_status);
9446 5832998 strcpy(binlog_global_snapshot_file, log_file_name);
9447 5832998 binlog_global_snapshot_position = m_binlog_file->position();
9448 5832998 mysql_mutex_unlock(&LOCK_status);
9449 5832998 }
9450
9451 213 void MYSQL_BIN_LOG::xlock(void) {
9452 213 mysql_mutex_lock(&LOCK_log);
9453
9454
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 213 times.
213 assert(!snapshot_lock_acquired);
9455
9456 /*
9457 We must ensure that no writes to binlog and no commits to storage engines
9458 occur after function is called for START TRANSACTION FOR CONSISTENT
9459 SNAPSHOT. With binlog_order_commits=1 (the default) flushing to binlog is
9460 performed under the LOCK_log mutex and commits are done under the
9461 LOCK_commit mutex, both in the stage leader thread. So acquiring those 2
9462 mutexes is sufficient to guarantee atomicity.
9463
9464 With binlog_order_commits=0 commits are performed in parallel by separate
9465 threads with each acquiring a shared lock on LOCK_consistent_snapshot.
9466
9467 binlog_order_commits is a dynamic variable, so we have to keep track what
9468 primitives should be used in xunlock().
9469 */
9470
1/2
✓ Branch 0 taken 213 times.
✗ Branch 1 not taken.
213 if (opt_binlog_order_commits) {
9471 213 mysql_mutex_lock(&LOCK_commit);
9472 } else {
9473 snapshot_lock_acquired = true;
9474 mysql_rwlock_wrlock(&LOCK_consistent_snapshot);
9475 }
9476 213 }
9477
9478 213 void MYSQL_BIN_LOG::xunlock(void) {
9479
1/2
✓ Branch 0 taken 213 times.
✗ Branch 1 not taken.
213 if (!snapshot_lock_acquired) {
9480 213 mysql_mutex_unlock(&LOCK_commit);
9481 } else {
9482 mysql_rwlock_unlock(&LOCK_consistent_snapshot);
9483 snapshot_lock_acquired = false;
9484 }
9485
9486 213 mysql_mutex_unlock(&LOCK_log);
9487 213 }
9488
9489 /*
9490 Copy out the non-directory part of binlog position filename for the
9491 `binlog_snapshot_file' status variable, same way as it is done for
9492 SHOW MASTER STATUS.
9493 */
9494 106704 static void set_binlog_snapshot_file(const char *src) {
9495 106704 mysql_mutex_assert_owner(&LOCK_status);
9496
9497 106704 int dir_len = dirname_length(src);
9498 106704 strmake(binlog_snapshot_file, src + dir_len,
9499 sizeof(binlog_snapshot_file) - 1);
9500 106704 }
9501
9502
9503
9504 9 void MYSQL_BIN_LOG::report_missing_purged_gtids(
9505 const Gtid_set *slave_executed_gtid_set, std::string &errmsg) {
9506
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 DBUG_TRACE;
9507
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 THD *thd = current_thd;
9508
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 Gtid_set gtid_missing(gtid_state->get_lost_gtids()->get_sid_map());
9509
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 gtid_missing.add_gtid_set(gtid_state->get_lost_gtids());
9510
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 gtid_missing.remove_gtid_set(slave_executed_gtid_set);
9511
9512 9 String tmp_uuid;
9513
9514 /* Protects thd->user_vars. */
9515
2/4
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
9 mysql_mutex_lock(&current_thd->LOCK_thd_data);
9516
3/6
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
9 const auto it = current_thd->user_vars.find("replica_uuid");
9517
4/8
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 9 times.
✗ Branch 7 not taken.
9 if (it != current_thd->user_vars.end() && it->second->length() > 0) {
9518
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 tmp_uuid.copy(it->second->ptr(), it->second->length(), nullptr);
9519 }
9520
2/4
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
9 mysql_mutex_unlock(&current_thd->LOCK_thd_data);
9521
9522 9 char *missing_gtids = nullptr;
9523 9 char *slave_executed_gtids = nullptr;
9524
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 gtid_missing.to_string(&missing_gtids);
9525
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 slave_executed_gtid_set->to_string(&slave_executed_gtids);
9526
9527 /*
9528 Log the information about the missing purged GTIDs to the error log.
9529 */
9530
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 std::ostringstream log_info;
9531
3/6
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
9 log_info << "The missing transactions are '" << missing_gtids << "'";
9532
9533
9/18
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 9 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 9 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 9 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 9 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 9 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 9 times.
✗ Branch 17 not taken.
9 LogErr(WARNING_LEVEL, ER_FOUND_MISSING_GTIDS, tmp_uuid.ptr(),
9534 log_info.str().c_str());
9535
9536 /*
9537 Send the information about the slave executed GTIDs and missing
9538 purged GTIDs to slave if the message is less than MYSQL_ERRMSG_SIZE.
9539 */
9540
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 std::ostringstream gtid_info;
9541 gtid_info << "The GTID set sent by the slave is '" << slave_executed_gtids
9542
5/10
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 9 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 9 times.
✗ Branch 9 not taken.
9 << "', and the missing transactions are '" << missing_gtids << "'";
9543
2/4
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
9 errmsg.assign(ER_THD(thd, ER_MASTER_HAS_PURGED_REQUIRED_GTIDS));
9544
9545 /* Don't consider the "%s" in the format string. Subtract 2 from the
9546 total length */
9547
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 int total_length = (errmsg.length() - 2 + gtid_info.str().length());
9548
9549
3/4
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 6 times.
9 DBUG_EXECUTE_IF("simulate_long_missing_gtids",
9550 { total_length = MYSQL_ERRMSG_SIZE + 1; });
9551
9552
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 6 times.
9 if (total_length > MYSQL_ERRMSG_SIZE)
9553
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
3 gtid_info.str(
9554 "The GTID sets and the missing purged transactions are too"
9555 " long to print in this message. For more information,"
9556 " please see the master's error log or the manual for"
9557 " GTID_SUBTRACT");
9558
9559 /* Buffer for formatting the message about the missing GTIDs. */
9560 9 char buff[MYSQL_ERRMSG_SIZE] = {0};
9561
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 snprintf(buff, MYSQL_ERRMSG_SIZE, errmsg.c_str(), gtid_info.str().c_str());
9562
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 errmsg.assign(buff);
9563
9564
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 my_free(missing_gtids);
9565
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 my_free(slave_executed_gtids);
9566 9 }
9567
9568 1 void MYSQL_BIN_LOG::report_missing_gtids(
9569 const Gtid_set *previous_gtid_set, const Gtid_set *slave_executed_gtid_set,
9570 std::string &errmsg) {
9571
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 DBUG_TRACE;
9572
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 THD *thd = current_thd;
9573 1 char *missing_gtids = nullptr;
9574 1 char *slave_executed_gtids = nullptr;
9575
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 Gtid_set gtid_missing(slave_executed_gtid_set->get_sid_map());
9576
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 gtid_missing.add_gtid_set(slave_executed_gtid_set);
9577
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 gtid_missing.remove_gtid_set(previous_gtid_set);
9578
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 gtid_missing.to_string(&missing_gtids);
9579
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 slave_executed_gtid_set->to_string(&slave_executed_gtids);
9580
9581 1 String tmp_uuid;
9582
9583 /* Protects thd->user_vars. */
9584
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 mysql_mutex_lock(&current_thd->LOCK_thd_data);
9585
3/6
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 const auto it = current_thd->user_vars.find("replica_uuid");
9586
4/8
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
1 if (it != current_thd->user_vars.end() && it->second->length() > 0) {
9587
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 tmp_uuid.copy(it->second->ptr(), it->second->length(), nullptr);
9588 }
9589
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 mysql_mutex_unlock(&current_thd->LOCK_thd_data);
9590
9591 /*
9592 Log the information about the missing purged GTIDs to the error log.
9593 */
9594
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 std::ostringstream log_info;
9595 log_info << "If the binary log files have been deleted from disk,"
9596 " check the consistency of 'GTID_PURGED' variable."
9597 " The missing transactions are '"
9598
3/6
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 << missing_gtids << "'";
9599
9/18
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 1 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 1 times.
✗ Branch 17 not taken.
1 LogErr(WARNING_LEVEL, ER_FOUND_MISSING_GTIDS, tmp_uuid.ptr(),
9600 log_info.str().c_str());
9601 /*
9602 Send the information about the slave executed GTIDs and missing
9603 purged GTIDs to slave if the message is less than MYSQL_ERRMSG_SIZE.
9604 */
9605
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 std::ostringstream gtid_info;
9606 gtid_info << "The GTID set sent by the slave is '" << slave_executed_gtids
9607
5/10
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
1 << "', and the missing transactions are '" << missing_gtids << "'";
9608
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 errmsg.assign(ER_THD(thd, ER_MASTER_HAS_PURGED_REQUIRED_GTIDS));
9609
9610 /* Don't consider the "%s" in the format string. Subtract 2 from the
9611 total length */
9612
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1 if ((errmsg.length() - 2 + gtid_info.str().length()) > MYSQL_ERRMSG_SIZE)
9613 gtid_info.str(
9614 "The GTID sets and the missing purged transactions are too"
9615 " long to print in this message. For more information,"
9616 " please see the master's error log or the manual for"
9617 " GTID_SUBTRACT");
9618 /* Buffer for formatting the message about the missing GTIDs. */
9619 1 char buff[MYSQL_ERRMSG_SIZE] = {0};
9620
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 snprintf(buff, MYSQL_ERRMSG_SIZE, errmsg.c_str(), gtid_info.str().c_str());
9621
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 errmsg.assign(buff);
9622
9623
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 my_free(missing_gtids);
9624
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 my_free(slave_executed_gtids);
9625 1 }
9626
9627 1966785 void MYSQL_BIN_LOG::update_binlog_end_pos(bool need_lock) {
9628
2/2
✓ Branch 0 taken 191241 times.
✓ Branch 1 taken 1775544 times.
1966785 if (need_lock)
9629 191241 lock_binlog_end_pos();
9630 else
9631 1775544 mysql_mutex_assert_owner(&LOCK_binlog_end_pos);
9632 1966785 atomic_binlog_end_pos = m_binlog_file->position();
9633 1966785 signal_update();
9634
2/2
✓ Branch 0 taken 191241 times.
✓ Branch 1 taken 1775544 times.
1966785 if (need_lock) unlock_binlog_end_pos();
9635 1966785 }
9636
9637 5728496 inline void MYSQL_BIN_LOG::update_binlog_end_pos(const char *file,
9638 my_off_t pos) {
9639 5728496 lock_binlog_end_pos();
9640
6/6
✓ Branch 0 taken 5728495 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 5728494 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 5728494 times.
✓ Branch 5 taken 2 times.
5728496 if (is_active(file) && (pos > atomic_binlog_end_pos))
9641 5728494 atomic_binlog_end_pos = pos;
9642 5728496 signal_update();
9643 5728496 unlock_binlog_end_pos();
9644 5728496 }
9645
9646 5791540 bool THD::is_binlog_cache_empty(bool is_transactional) const {
9647
1/2
✓ Branch 0 taken 5791559 times.
✗ Branch 1 not taken.
5791540 DBUG_TRACE;
9648
9649 // If opt_bin_log==0, it is not safe to call thd_get_cache_mngr
9650 // because binlog_hton has not been completely set up.
9651
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5791559 times.
5791559 assert(opt_bin_log);
9652
1/2
✓ Branch 0 taken 5791573 times.
✗ Branch 1 not taken.
5791559 binlog_cache_mngr *cache_mngr = thd_get_cache_mngr(this);
9653
9654 // cache_mngr is NULL until we call thd->binlog_setup_trx_data, so
9655 // we assert that this has been done.
9656
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5791573 times.
5791573 assert(cache_mngr != nullptr);
9657
9658 binlog_cache_data *cache_data =
9659 5791573 cache_mngr->get_binlog_cache_data(is_transactional);
9660
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5791536 times.
5791536 assert(cache_data != nullptr);
9661
9662
1/2
✓ Branch 0 taken 5791573 times.
✗ Branch 1 not taken.
11583110 return cache_data->is_binlog_empty();
9663 5791573 }
9664
9665 /*
9666 These functions are placed in this file since they need access to
9667 binlog_hton, which has internal linkage.
9668 */
9669
9670 16974669 int THD::binlog_setup_trx_data() {
9671
1/2
✓ Branch 0 taken 16975106 times.
✗ Branch 1 not taken.
16974669 DBUG_TRACE;
9672
1/2
✓ Branch 0 taken 16974957 times.
✗ Branch 1 not taken.
16975106 binlog_cache_mngr *cache_mngr = thd_get_cache_mngr(this);
9673
9674
2/2
✓ Branch 0 taken 16928315 times.
✓ Branch 1 taken 46642 times.
16974957 if (cache_mngr) /* Already set up */ {
9675 16928021 if (Rpl_thd_context::TX_RPL_STAGE_BEGIN ==
9676
3/4
✓ Branch 0 taken 16928021 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 98193 times.
✓ Branch 3 taken 16829828 times.
16928315 rpl_thd_ctx.get_tx_rpl_delegate_stage_status())
9677
1/2
✓ Branch 0 taken 98253 times.
✗ Branch 1 not taken.
98193 rpl_thd_ctx.set_tx_rpl_delegate_stage_status(
9678 Rpl_thd_context::TX_RPL_STAGE_CACHE_CREATED);
9679 16928081 return 0;
9680 }
9681
9682
1/2
✓ Branch 0 taken 46675 times.
✗ Branch 1 not taken.
46642 cache_mngr = (binlog_cache_mngr *)my_malloc(key_memory_binlog_cache_mngr,
9683 sizeof(binlog_cache_mngr),
9684 MYF(MY_ZEROFILL));
9685
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 46675 times.
46675 if (!cache_mngr) {
9686 return 1; // Didn't manage to set it up
9687 }
9688
9689 93349 cache_mngr = new (cache_mngr)
9690 binlog_cache_mngr(&binlog_stmt_cache_use, &binlog_stmt_cache_disk_use,
9691
1/2
✓ Branch 0 taken 46674 times.
✗ Branch 1 not taken.
46675 &binlog_cache_use, &binlog_cache_disk_use);
9692
2/4
✓ Branch 0 taken 46677 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 46677 times.
46674 if (cache_mngr->init()) {
9693 cache_mngr->~binlog_cache_mngr();
9694 my_free(cache_mngr);
9695 return 1;
9696 }
9697 46675 if (Rpl_thd_context::TX_RPL_STAGE_BEGIN ==
9698
3/4
✓ Branch 0 taken 46675 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5968 times.
✓ Branch 3 taken 40707 times.
46677 rpl_thd_ctx.get_tx_rpl_delegate_stage_status())
9699
1/2
✓ Branch 0 taken 5968 times.
✗ Branch 1 not taken.
5968 rpl_thd_ctx.set_tx_rpl_delegate_stage_status(
9700 Rpl_thd_context::TX_RPL_STAGE_CACHE_CREATED);
9701
9702
3/8
✓ Branch 0 taken 46676 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 46677 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 46677 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
46675 DBUG_PRINT("debug", ("Set ha_data slot %d to 0x%llx", binlog_hton->slot,
9703 (ulonglong)cache_mngr));
9704
1/2
✓ Branch 0 taken 46677 times.
✗ Branch 1 not taken.
46677 thd_set_ha_data(this, binlog_hton, cache_mngr);
9705
9706 46677 return 0;
9707 16974758 }
9708
9709 /**
9710
9711 */
9712 11028744 void register_binlog_handler(THD *thd, bool trx) {
9713
1/2
✓ Branch 0 taken 11029290 times.
✗ Branch 1 not taken.
11028744 DBUG_TRACE;
9714 /*
9715 If this is the first call to this function while processing a statement,
9716 the transactional cache does not have a savepoint defined. So, in what
9717 follows:
9718 . an implicit savepoint is defined;
9719 . callbacks are registered;
9720 . binary log is set as read/write.
9721
9722 The savepoint allows for truncating the trx-cache transactional changes
9723 fail. Callbacks are necessary to flush caches upon committing or rolling
9724 back a statement or a transaction. However, notifications do not happen
9725 if the binary log is set as read/write.
9726 */
9727
1/2
✓ Branch 0 taken 11029471 times.
✗ Branch 1 not taken.
11029290 binlog_cache_mngr *cache_mngr = thd_get_cache_mngr(thd);
9728
2/2
✓ Branch 0 taken 11014750 times.
✓ Branch 1 taken 14490 times.
11029471 if (cache_mngr->trx_cache.get_prev_position() == MY_OFF_T_UNDEF) {
9729 /*
9730 Set an implicit savepoint in order to be able to truncate a trx-cache.
9731 */
9732 11014750 my_off_t pos = 0;
9733
1/2
✓ Branch 0 taken 11014842 times.
✗ Branch 1 not taken.
11014750 binlog_trans_log_savepos(thd, &pos);
9734
1/2
✓ Branch 0 taken 11014883 times.
✗ Branch 1 not taken.
11014842 cache_mngr->trx_cache.set_prev_position(pos);
9735
9736 /*
9737 Set callbacks in order to be able to call commit or rollback.
9738 */
9739
3/4
✓ Branch 0 taken 5867119 times.
✓ Branch 1 taken 5147764 times.
✓ Branch 2 taken 5867111 times.
✗ Branch 3 not taken.
11014883 if (trx) trans_register_ha(thd, true, binlog_hton, nullptr);
9740
1/2
✓ Branch 0 taken 11014867 times.
✗ Branch 1 not taken.
11014875 trans_register_ha(thd, false, binlog_hton, nullptr);
9741
9742 /*
9743 Set the binary log as read/write otherwise callbacks are not called.
9744 */
9745
2/4
✓ Branch 0 taken 11014968 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11014890 times.
✗ Branch 3 not taken.
11014867 thd->get_ha_data(binlog_hton->slot)->ha_info[0].set_trx_read_write();
9746 }
9747 11029380 }
9748
9749 /**
9750 Function to start a statement and optionally a transaction for the
9751 binary log.
9752
9753 This function does three things:
9754 - Starts a transaction if not in autocommit mode or if a BEGIN
9755 statement has been seen.
9756
9757 - Start a statement transaction to allow us to truncate the cache.
9758
9759 - Save the current binlog position so that we can roll back the
9760 statement by truncating the cache.
9761
9762 We only update the saved position if the old one was undefined,
9763 the reason is that there are some cases (e.g., for CREATE-SELECT)
9764 where the position is saved twice (e.g., both in
9765 Query_result_create::prepare() and THD::binlog_write_table_map()), but
9766 we should use the first. This means that calls to this function
9767 can be used to start the statement before the first table map
9768 event, to include some extra events.
9769
9770 Note however that IMMEDIATE_LOGGING implies that the statement is
9771 written without BEGIN/COMMIT.
9772
9773 @param thd Thread variable
9774 @param start_event The first event requested to be written into the
9775 binary log
9776 */
9777 11132673 static int binlog_start_trans_and_stmt(THD *thd, Log_event *start_event) {
9778
1/2
✓ Branch 0 taken 11132882 times.
✗ Branch 1 not taken.
11132673 DBUG_TRACE;
9779
9780 /*
9781 Initialize the cache manager if this was not done yet.
9782 */
9783
2/4
✓ Branch 0 taken 11132775 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 11132775 times.
11132882 if (thd->binlog_setup_trx_data()) return 1;
9784
9785 /*
9786 Retrieve the appropriated cache.
9787 */
9788 11132775 bool is_transactional = start_event->is_using_trans_cache();
9789
1/2
✓ Branch 0 taken 11133196 times.
✗ Branch 1 not taken.
11132665 binlog_cache_mngr *cache_mngr = thd_get_cache_mngr(thd);
9790 binlog_cache_data *cache_data =
9791 11133196 cache_mngr->get_binlog_cache_data(is_transactional);
9792
9793 /*
9794 If the event is requesting immediate logging, there is no need to go
9795 further down and set savepoint and register callbacks.
9796 */
9797
2/2
✓ Branch 0 taken 103648 times.
✓ Branch 1 taken 11029030 times.
11132589 if (start_event->is_using_immediate_logging()) return 0;
9798
9799
1/2
✓ Branch 0 taken 11029425 times.
✗ Branch 1 not taken.
11029030 register_binlog_handler(thd, thd->in_multi_stmt_transaction_mode());
9800
9801 /* Transactional DDL is logged traditionally without BEGIN. */
9802
2/2
✓ Branch 0 taken 265694 times.
✓ Branch 1 taken 10763222 times.
11029425 if (is_atomic_ddl_event(start_event)) return 0;
9803
9804 /*
9805 If the cache is empty log "BEGIN" at the beginning of every transaction.
9806 Here, a transaction is either a BEGIN..COMMIT/ROLLBACK block or a single
9807 statement in autocommit mode.
9808 */
9809
3/4
✓ Branch 0 taken 10763623 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5512204 times.
✓ Branch 3 taken 5251419 times.
10763222 if (cache_data->is_binlog_empty()) {
9810 static const char begin[] = "BEGIN";
9811 5512204 const char *query = nullptr;
9812 char buf[XID::ser_buf_size];
9813 char xa_start[sizeof("XA START") + 1 + sizeof(buf)];
9814 5512204 XID_STATE *xs = thd->get_transaction()->xid_state();
9815 5512279 int qlen = sizeof(begin) - 1;
9816
9817
6/6
✓ Branch 0 taken 5134130 times.
✓ Branch 1 taken 378149 times.
✓ Branch 2 taken 660 times.
✓ Branch 3 taken 5133491 times.
✓ Branch 4 taken 660 times.
✓ Branch 5 taken 5511640 times.
5512279 if (is_transactional && xs->has_state(XID_STATE::XA_ACTIVE)) {
9818 /*
9819 XA-prepare logging case.
9820 */
9821 660 qlen = sprintf(xa_start, "XA START %s", xs->get_xid()->serialize(buf));
9822 660 query = xa_start;
9823 } else {
9824 /*
9825 Regular transaction case.
9826 */
9827 5511640 query = begin;
9828 }
9829
9830 Query_log_event qinfo(thd, query, qlen, is_transactional, false, true, 0,
9831
1/2
✓ Branch 0 taken 5511763 times.
✗ Branch 1 not taken.
5512300 true);
9832
2/4
✓ Branch 0 taken 5512222 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5512222 times.
5511763 if (cache_data->write_event(&qinfo)) return 1;
9833
1/2
✓ Branch 0 taken 5511624 times.
✗ Branch 1 not taken.
5512222 }
9834
9835 10763043 return 0;
9836 11132346 }
9837
9838 /**
9839 This function writes a table map to the binary log.
9840 Note that in order to keep the signature uniform with related methods,
9841 we use a redundant parameter to indicate whether a transactional table
9842 was changed or not.
9843 Sometimes it will write a Rows_query_log_event into binary log before
9844 the table map too.
9845
9846 @param table a pointer to the table.
9847 @param is_transactional @c true indicates a transactional table,
9848 otherwise @c false a non-transactional.
9849 @param binlog_rows_query @c true indicates a Rows_query log event
9850 will be binlogged before table map,
9851 otherwise @c false indicates it will not
9852 be binlogged.
9853 @return
9854 nonzero if an error pops up when writing the table map event
9855 or the Rows_query log event.
9856 */
9857 10438262 int THD::binlog_write_table_map(TABLE *table, bool is_transactional,
9858 bool binlog_rows_query) {
9859 int error;
9860
1/2
✓ Branch 0 taken 10438635 times.
✗ Branch 1 not taken.
10438262 DBUG_TRACE;
9861
5/8
✓ Branch 0 taken 10438516 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10438597 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 16 times.
✓ Branch 5 taken 10438581 times.
✓ Branch 6 taken 16 times.
✗ Branch 7 not taken.
10438635 DBUG_PRINT("enter", ("table: %p (%s: #%llu)", table, table->s->table_name.str,
9862 table->s->table_map_id.id()));
9863
9864 /* Pre-conditions */
9865
3/4
✓ Branch 0 taken 10438561 times.
✓ Branch 1 taken 54 times.
✓ Branch 2 taken 10438629 times.
✗ Branch 3 not taken.
10438597 assert(is_current_stmt_binlog_format_row() && mysql_bin_log.is_open());
9866
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10438257 times.
10438629 assert(table->s->table_map_id.is_valid());
9867
9868 10438257 Table_map_log_event the_event(this, table, table->s->table_map_id,
9869
1/2
✓ Branch 0 taken 10438457 times.
✗ Branch 1 not taken.
10438257 is_transactional);
9870
9871
1/2
✓ Branch 0 taken 10438611 times.
✗ Branch 1 not taken.
10438457 binlog_start_trans_and_stmt(this, &the_event);
9872
9873
1/2
✓ Branch 0 taken 10438614 times.
✗ Branch 1 not taken.
10438611 binlog_cache_mngr *const cache_mngr = thd_get_cache_mngr(this);
9874
9875 binlog_cache_data *cache_data =
9876 10438614 cache_mngr->get_binlog_cache_data(is_transactional);
9877
9878
7/8
✓ Branch 0 taken 71 times.
✓ Branch 1 taken 10438541 times.
✓ Branch 2 taken 73 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 71 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 71 times.
✓ Branch 7 taken 10438543 times.
10438612 if (binlog_rows_query && this->query().str) {
9879 /* Write the Rows_query_log_event into binlog before the table map */
9880 142 Rows_query_log_event rows_query_ev(this, this->query().str,
9881
3/6
✓ Branch 0 taken 71 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 71 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 71 times.
✗ Branch 5 not taken.
71 this->query().length);
9882
2/4
✓ Branch 0 taken 71 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 71 times.
71 if ((error = cache_data->write_event(&rows_query_ev))) return error;
9883
1/2
✓ Branch 0 taken 71 times.
✗ Branch 1 not taken.
71 }
9884
9885
2/4
✓ Branch 0 taken 10438632 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 10438632 times.
10438614 if ((error = cache_data->write_event(&the_event))) return error;
9886
9887 10438632 binlog_table_maps++;
9888 10438632 return 0;
9889 10438632 }
9890
9891 /**
9892 This function retrieves a pending row event from a cache which is
9893 specified through the parameter @c is_transactional. Respectively, when it
9894 is @c true, the pending event is returned from the transactional cache.
9895 Otherwise from the non-transactional cache.
9896
9897 @param is_transactional @c true indicates a transactional cache,
9898 otherwise @c false a non-transactional.
9899 @return
9900 The row event if any.
9901 */
9902 154366012 Rows_log_event *THD::binlog_get_pending_rows_event(
9903 bool is_transactional) const {
9904 154366012 Rows_log_event *rows = nullptr;
9905 154366012 binlog_cache_mngr *const cache_mngr = thd_get_cache_mngr(this);
9906
9907 /*
9908 This is less than ideal, but here's the story: If there is no cache_mngr,
9909 prepare_pending_rows_event() has never been called (since the cache_mngr
9910 is set up there). In that case, we just return NULL.
9911 */
9912
2/2
✓ Branch 0 taken 133311451 times.
✓ Branch 1 taken 21063534 times.
154374985 if (cache_mngr) {
9913 binlog_cache_data *cache_data =
9914 133311451 cache_mngr->get_binlog_cache_data(is_transactional);
9915
9916 133291681 rows = cache_data->pending();
9917 }
9918 154374964 return (rows);
9919 }
9920
9921 /**
9922 @param db_param db name c-string to be inserted into alphabetically sorted
9923 THD::binlog_accessed_db_names list.
9924
9925 Note, that space for both the data and the node
9926 struct are allocated in THD::main_mem_root.
9927 The list lasts for the top-level query time and is reset
9928 in @c THD::cleanup_after_query().
9929 */
9930 1494686 void THD::add_to_binlog_accessed_dbs(const char *db_param) {
9931 char *after_db;
9932 /*
9933 binlog_accessed_db_names list is to maintain the database
9934 names which are referenced in a given command.
9935 Prior to bug 17806014 fix, 'main_mem_root' memory root used
9936 to store this list. The 'main_mem_root' scope is till the end
9937 of the query. Hence it caused increasing memory consumption
9938 problem in big procedures like the ones mentioned below.
9939 Eg: CALL p1() where p1 is having 1,00,000 create and drop tables.
9940 'main_mem_root' is freed only at the end of the command CALL p1()'s
9941 execution. But binlog_accessed_db_names list scope is only till the
9942 individual statements specified the procedure(create/drop statements).
9943 Hence the memory allocated in 'main_mem_root' was left uncleared
9944 until the p1's completion, even though it is not required after
9945 completion of individual statements.
9946
9947 Instead of using 'main_mem_root' whose scope is complete query execution,
9948 now the memroot is changed to use 'thd->mem_root' whose scope is until the
9949 individual statement in CALL p1(). 'thd->mem_root' is set to
9950 'execute_mem_root' in the context of procedure and it's scope is till the
9951 individual statement in CALL p1() and thd->memroot is equal to
9952 'main_mem_root' in the context of a normal 'top level query'.
9953
9954 Eg: a) create table t1(i int); => If this function is called while
9955 processing this statement, thd->memroot is equal to &main_mem_root
9956 which will be freed immediately after executing this statement.
9957 b) CALL p1() -> p1 contains create table t1(i int); => If this function
9958 is called while processing create table statement which is inside
9959 a stored procedure, then thd->memroot is equal to 'execute_mem_root'
9960 which will be freed immediately after executing this statement.
9961 In both a and b case, thd->memroot will be freed immediately and will not
9962 increase memory consumption.
9963
9964 A special case(stored functions/triggers):
9965 Consider the following example:
9966 create function f1(i int) returns int
9967 begin
9968 insert into db1.t1 values (1);
9969 insert into db2.t1 values (2);
9970 end;
9971 When we are processing SELECT f1(), the list should contain db1, db2 names.
9972 Since thd->mem_root contains 'execute_mem_root' in the context of
9973 stored function, the mem root will be freed after adding db1 in
9974 the list and when we are processing the second statement and when we try
9975 to add 'db2' in the db1's list, it will lead to crash as db1's memory
9976 is already freed. To handle this special case, if in_sub_stmt is set
9977 (which is true in case of stored functions/triggers), we use &main_mem_root,
9978 if not set we will use thd->memroot which changes it's value to
9979 'execute_mem_root' or '&main_mem_root' depends on the context.
9980 */
9981
2/2
✓ Branch 0 taken 359 times.
✓ Branch 1 taken 1494327 times.
1494686 MEM_ROOT *db_mem_root = in_sub_stmt ? &main_mem_root : mem_root;
9982
9983
2/2
✓ Branch 0 taken 1190191 times.
✓ Branch 1 taken 304495 times.
1494686 if (!binlog_accessed_db_names)
9984
1/2
✓ Branch 0 taken 1190201 times.
✗ Branch 1 not taken.
1190191 binlog_accessed_db_names = new (db_mem_root) List<char>;
9985
9986
2/2
✓ Branch 0 taken 392 times.
✓ Branch 1 taken 1494225 times.
1494617 if (binlog_accessed_db_names->elements > MAX_DBS_IN_EVENT_MTS) {
9987 392 push_warning_printf(
9988 this, Sql_condition::SL_WARNING, ER_MTS_UPDATED_DBS_GREATER_MAX,
9989 ER_THD(this, ER_MTS_UPDATED_DBS_GREATER_MAX), MAX_DBS_IN_EVENT_MTS);
9990 392 return;
9991 }
9992
9993 1494225 after_db = strdup_root(db_mem_root, db_param);
9994
9995 /*
9996 sorted insertion is implemented with first rearranging data
9997 (pointer to char*) of the links and final appending of the least
9998 ordered data to create a new link in the list.
9999 */
10000
2/2
✓ Branch 0 taken 304230 times.
✓ Branch 1 taken 1190336 times.
1494566 if (binlog_accessed_db_names->elements != 0) {
10001
1/2
✓ Branch 0 taken 304230 times.
✗ Branch 1 not taken.
304230 List_iterator<char> it(*get_binlog_accessed_db_names());
10002
10003
2/2
✓ Branch 0 taken 377220 times.
✓ Branch 1 taken 14834 times.
392054 while (it++) {
10004 377220 char *swap = nullptr;
10005 377220 char **ref_cur_db = it.ref();
10006 377220 int cmp = strcmp(after_db, *ref_cur_db);
10007
10008
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 377220 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
377220 assert(!swap || cmp < 0);
10009
10010
2/2
✓ Branch 0 taken 289396 times.
✓ Branch 1 taken 87824 times.
377220 if (cmp == 0) {
10011 289396 after_db = nullptr; /* dup to ignore */
10012 289396 break;
10013
3/4
✓ Branch 0 taken 87824 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17859 times.
✓ Branch 3 taken 69965 times.
87824 } else if (swap || cmp > 0) {
10014 17859 swap = *ref_cur_db;
10015 17859 *ref_cur_db = after_db;
10016 17859 after_db = swap;
10017 }
10018 }
10019 }
10020
2/2
✓ Branch 0 taken 1204848 times.
✓ Branch 1 taken 289718 times.
1494566 if (after_db) binlog_accessed_db_names->push_back(after_db, db_mem_root);
10021 }
10022
10023 /*
10024 Tells if two (or more) tables have auto_increment columns and we want to
10025 lock those tables with a write lock.
10026
10027 SYNOPSIS
10028 has_two_write_locked_tables_with_auto_increment
10029 tables Table list
10030
10031 NOTES:
10032 Call this function only when you have established the list of all tables
10033 which you'll want to update (including stored functions, triggers, views
10034 inside your statement).
10035 */
10036
10037 858935 static bool has_write_table_with_auto_increment(TABLE_LIST *tables) {
10038
2/2
✓ Branch 0 taken 1691383 times.
✓ Branch 1 taken 745546 times.
2436929 for (TABLE_LIST *table = tables; table; table = table->next_global) {
10039 /* we must do preliminary checks as table->table may be NULL */
10040
6/6
✓ Branch 0 taken 1508778 times.
✓ Branch 1 taken 183064 times.
✓ Branch 2 taken 548755 times.
✓ Branch 3 taken 960023 times.
✓ Branch 4 taken 113848 times.
✓ Branch 5 taken 1577994 times.
2240138 if (!table->is_placeholder() && table->table->found_next_number_field &&
10041
2/2
✓ Branch 0 taken 113848 times.
✓ Branch 1 taken 434907 times.
548755 (table->lock_descriptor().type >= TL_WRITE_ALLOW_WRITE))
10042 113848 return true;
10043 }
10044
10045 745546 return false;
10046 }
10047
10048 /*
10049 checks if we have select tables in the table list and write tables
10050 with auto-increment column.
10051
10052 SYNOPSIS
10053 has_two_write_locked_tables_with_auto_increment_and_query_block
10054 tables Table list
10055
10056 RETURN VALUES
10057
10058 -true if the table list has at least one table with auto-increment column
10059 and at least one table to select from.
10060 -false otherwise
10061 */
10062
10063 849637 static bool has_write_table_with_auto_increment_and_query_block(
10064 TABLE_LIST *tables) {
10065 849637 bool has_query_block = false;
10066 849637 bool has_auto_increment_tables = has_write_table_with_auto_increment(tables);
10067
2/2
✓ Branch 0 taken 1219103 times.
✓ Branch 1 taken 435411 times.
1654514 for (TABLE_LIST *table = tables; table; table = table->next_global) {
10068
4/4
✓ Branch 0 taken 1036796 times.
✓ Branch 1 taken 182407 times.
✓ Branch 2 taken 414696 times.
✓ Branch 3 taken 804436 times.
2255828 if (!table->is_placeholder() &&
10069
2/2
✓ Branch 0 taken 414697 times.
✓ Branch 1 taken 622028 times.
1036796 (table->lock_descriptor().type <= TL_READ_NO_INSERT)) {
10070 414696 has_query_block = true;
10071 414696 break;
10072 }
10073 }
10074
4/4
✓ Branch 0 taken 414697 times.
✓ Branch 1 taken 435410 times.
✓ Branch 2 taken 406 times.
✓ Branch 3 taken 414291 times.
850107 return (has_query_block && has_auto_increment_tables);
10075 }
10076
10077 /*
10078 Tells if there is a table whose auto_increment column is a part
10079 of a compound primary key while is not the first column in
10080 the table definition.
10081
10082 @param tables Table list
10083
10084 @return true if the table exists, fais if does not.
10085 */
10086
10087 849637 static bool has_write_table_auto_increment_not_first_in_pk(TABLE_LIST *tables) {
10088
2/2
✓ Branch 0 taken 1681221 times.
✓ Branch 1 taken 850083 times.
2531304 for (TABLE_LIST *table = tables; table; table = table->next_global) {
10089 /* we must do preliminary checks as table->table may be NULL */
10090
2/2
✓ Branch 0 taken 549003 times.
✓ Branch 1 taken 949671 times.
3179895 if (!table->is_placeholder() && table->table->found_next_number_field &&
10091
6/6
✓ Branch 0 taken 1498674 times.
✓ Branch 1 taken 183003 times.
✓ Branch 2 taken 113870 times.
✓ Branch 3 taken 435135 times.
✓ Branch 4 taken 12 times.
✓ Branch 5 taken 1681667 times.
3294221 (table->lock_descriptor().type >= TL_WRITE_ALLOW_WRITE) &&
10092
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 113858 times.
113870 table->table->s->next_number_keypart != 0)
10093 12 return true;
10094 }
10095
10096 850083 return false;
10097 }
10098
10099 /**
10100 Checks if a table has a column with a non-deterministic DEFAULT expression.
10101 */
10102 10784 static bool has_nondeterministic_default(const TABLE *table) {
10103 21568 return std::any_of(
10104 10784 table->field, table->field + table->s->fields, [](const Field *field) {
10105
4/4
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 19415 times.
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 14 times.
19469 return field->m_default_val_expr != nullptr &&
10106 19469 field->m_default_val_expr->get_stmt_unsafe_flags() != 0;
10107 10784 });
10108 }
10109
10110 /**
10111 Checks if a TABLE_LIST contains a table that has been opened for writing, and
10112 that has a column with a non-deterministic DEFAULT expression.
10113 */
10114 9314 static bool has_write_table_with_nondeterministic_default(
10115 const TABLE_LIST *tables) {
10116
2/2
✓ Branch 0 taken 11222 times.
✓ Branch 1 taken 9301 times.
20523 for (const TABLE_LIST *table = tables; table != nullptr;
10117 11209 table = table->next_global) {
10118 /* we must do preliminary checks as table->table may be NULL */
10119 11222 if (!table->is_placeholder() &&
10120
6/6
✓ Branch 0 taken 11165 times.
✓ Branch 1 taken 57 times.
✓ Branch 2 taken 10784 times.
✓ Branch 3 taken 381 times.
✓ Branch 4 taken 13 times.
✓ Branch 5 taken 11209 times.
22006 table->lock_descriptor().type >= TL_WRITE_ALLOW_WRITE &&
10121
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 10771 times.
10784 has_nondeterministic_default(table->table))
10122 13 return true;
10123 }
10124 9301 return false;
10125 }
10126
10127 /**
10128 Checks if we have reads from ACL tables in table list.
10129
10130 @param thd Current thread
10131 @param tl_list TABLE_LIST used by current command.
10132
10133 @returns true, if we statement is unsafe, otherwise false.
10134 */
10135 849573 static bool has_acl_table_read(THD *thd, const TABLE_LIST *tl_list) {
10136
2/2
✓ Branch 0 taken 1681163 times.
✓ Branch 1 taken 849243 times.
2530406 for (const TABLE_LIST *tl = tl_list; tl != nullptr; tl = tl->next_global) {
10137
4/4
✓ Branch 0 taken 401446 times.
✓ Branch 1 taken 1280252 times.
✓ Branch 2 taken 868 times.
✓ Branch 3 taken 1680833 times.
2082612 if (is_acl_table_in_non_LTM(tl, thd->locked_tables_mode) &&
10138
2/2
✓ Branch 0 taken 400575 times.
✓ Branch 1 taken 871 times.
401446 (tl->lock_descriptor().type == TL_READ_DEFAULT ||
10139
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 400581 times.
400575 tl->lock_descriptor().type == TL_READ_HIGH_PRIORITY))
10140 868 return true;
10141 }
10142 849243 return false;
10143 }
10144
10145 /*
10146 Function to check whether the table in query uses a fulltext parser
10147 plugin or not.
10148
10149 @param s - table share pointer.
10150
10151 @retval true - The table uses fulltext parser plugin.
10152 @retval false - Otherwise.
10153 */
10154 11257551 static bool inline fulltext_unsafe_set(TABLE_SHARE *s) {
10155
2/2
✓ Branch 0 taken 14153481 times.
✓ Branch 1 taken 11256322 times.
25409803 for (unsigned int i = 0; i < s->keys; i++) {
10156
5/6
✓ Branch 0 taken 1229 times.
✓ Branch 1 taken 14152252 times.
✓ Branch 2 taken 1229 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1229 times.
✓ Branch 5 taken 14152252 times.
14153481 if ((s->key_info[i].flags & HA_USES_PARSER) && s->keys_in_use.is_set(i))
10157 1229 return true;
10158 }
10159 11256322 return false;
10160 }
10161 #ifndef NDEBUG
10162 144 const char *get_locked_tables_mode_name(
10163 enum_locked_tables_mode locked_tables_mode) {
10164
2/5
✓ Branch 0 taken 139 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
144 switch (locked_tables_mode) {
10165 139 case LTM_NONE:
10166 139 return "LTM_NONE";
10167 case LTM_LOCK_TABLES:
10168 return "LTM_LOCK_TABLES";
10169 5 case LTM_PRELOCKED:
10170 5 return "LTM_PRELOCKED";
10171 case LTM_PRELOCKED_UNDER_LOCK_TABLES:
10172 return "LTM_PRELOCKED_UNDER_LOCK_TABLES";
10173 default:
10174 return "Unknown table lock mode";
10175 }
10176 }
10177 #endif
10178
10179 /**
10180 Decide on logging format to use for the statement and issue errors
10181 or warnings as needed. The decision depends on the following
10182 parameters:
10183
10184 - The logging mode, i.e., the value of binlog_format. Can be
10185 statement, mixed, or row.
10186
10187 - The type of statement. There are three types of statements:
10188 "normal" safe statements; unsafe statements; and row injections.
10189 An unsafe statement is one that, if logged in statement format,
10190 might produce different results when replayed on the slave (e.g.,
10191 queries with a LIMIT clause). A row injection is either a BINLOG
10192 statement, or a row event executed by the slave's SQL thread.
10193
10194 - The capabilities of tables modified by the statement. The
10195 *capabilities vector* for a table is a set of flags associated
10196 with the table. Currently, it only includes two flags: *row
10197 capability flag* and *statement capability flag*.
10198
10199 The row capability flag is set if and only if the engine can
10200 handle row-based logging. The statement capability flag is set if
10201 and only if the table can handle statement-based logging.
10202
10203 Decision table for logging format
10204 ---------------------------------
10205
10206 The following table summarizes how the format and generated
10207 warning/error depends on the tables' capabilities, the statement
10208 type, and the current binlog_format.
10209
10210 Row capable N NNNNNNNNN YYYYYYYYY YYYYYYYYY
10211 Statement capable N YYYYYYYYY NNNNNNNNN YYYYYYYYY
10212
10213 Statement type * SSSUUUIII SSSUUUIII SSSUUUIII
10214
10215 binlog_format * SMRSMRSMR SMRSMRSMR SMRSMRSMR
10216
10217 Logged format - SS-S----- -RR-RR-RR SRRSRR-RR
10218 Warning/Error 1 --2732444 5--5--6-- ---7--6--
10219
10220 Legend
10221 ------
10222
10223 Row capable: N - Some table not row-capable, Y - All tables row-capable
10224 Stmt capable: N - Some table not stmt-capable, Y - All tables stmt-capable
10225 Statement type: (S)afe, (U)nsafe, or Row (I)njection
10226 binlog_format: (S)TATEMENT, (M)IXED, or (R)OW
10227 Logged format: (S)tatement or (R)ow
10228 Warning/Error: Warnings and error messages are as follows:
10229
10230 1. Error: Cannot execute statement: binlogging impossible since both
10231 row-incapable engines and statement-incapable engines are
10232 involved.
10233
10234 2. Error: Cannot execute statement: binlogging impossible since
10235 BINLOG_FORMAT = ROW and at least one table uses a storage engine
10236 limited to statement-logging.
10237
10238 3. Error: Cannot execute statement: binlogging of unsafe statement
10239 is impossible when storage engine is limited to statement-logging
10240 and BINLOG_FORMAT = MIXED.
10241
10242 4. Error: Cannot execute row injection: binlogging impossible since
10243 at least one table uses a storage engine limited to
10244 statement-logging.
10245
10246 5. Error: Cannot execute statement: binlogging impossible since
10247 BINLOG_FORMAT = STATEMENT and at least one table uses a storage
10248 engine limited to row-logging.
10249
10250 6. Error: Cannot execute row injection: binlogging impossible since
10251 BINLOG_FORMAT = STATEMENT.
10252
10253 7. Warning: Unsafe statement binlogged in statement format since
10254 BINLOG_FORMAT = STATEMENT.
10255
10256 In addition, we can produce the following error (not depending on
10257 the variables of the decision diagram):
10258
10259 8. Error: Cannot execute statement: binlogging impossible since more
10260 than one engine is involved and at least one engine is
10261 self-logging.
10262
10263 9. Error: Do not allow users to modify a gtid_executed table
10264 explicitly by a XA transaction.
10265
10266 For each error case above, the statement is prevented from being
10267 logged, we report an error, and roll back the statement. For
10268 warnings, we set the thd->binlog_flags variable: the warning will be
10269 printed only if the statement is successfully logged.
10270
10271 @see THD::binlog_query
10272
10273 @param[in] tables Tables involved in the query
10274
10275 @retval 0 No error; statement can be logged.
10276 @retval -1 One of the error conditions above applies (1, 2, 4, 5, 6 or 9).
10277 */
10278
10279 39143915 int THD::decide_logging_format(TABLE_LIST *tables) {
10280
1/2
✓ Branch 0 taken 39145514 times.
✗ Branch 1 not taken.
39143915 DBUG_TRACE;
10281
6/10
✓ Branch 0 taken 39144920 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 39145476 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 151 times.
✓ Branch 5 taken 39145325 times.
✓ Branch 6 taken 151 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 151 times.
✗ Branch 9 not taken.
39145514 DBUG_PRINT("info", ("query: %s", query().str));
10282
5/8
✓ Branch 0 taken 39145456 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 39145568 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 151 times.
✓ Branch 5 taken 39145417 times.
✓ Branch 6 taken 151 times.
✗ Branch 7 not taken.
39145476 DBUG_PRINT("info", ("variables.binlog_format: %lu", variables.binlog_format));
10283
6/10
✓ Branch 0 taken 39145199 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 39145563 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 151 times.
✓ Branch 5 taken 39145412 times.
✓ Branch 6 taken 151 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 151 times.
✗ Branch 9 not taken.
39145568 DBUG_PRINT("info", ("lex->get_stmt_unsafe_flags(): 0x%x",
10284 lex->get_stmt_unsafe_flags()));
10285
10286 #if defined(ENABLED_DEBUG_SYNC)
10287
3/4
✓ Branch 0 taken 39145247 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 39094770 times.
✓ Branch 3 taken 50477 times.
39145563 if (!is_attachable_ro_transaction_active())
10288
3/4
✓ Branch 0 taken 36292777 times.
✓ Branch 1 taken 2801639 times.
✓ Branch 2 taken 36293471 times.
✗ Branch 3 not taken.
39094770 DEBUG_SYNC(this, "begin_decide_logging_format");
10289 #endif
10290
10291 39145587 reset_binlog_local_stmt_filter();
10292
10293 /*
10294 We should not decide logging format if the binlog is closed or
10295 binlogging is off, or if the statement is filtered out from the
10296 binlog by filtering rules.
10297 */
10298
6/6
✓ Branch 0 taken 34115826 times.
✓ Branch 1 taken 5029587 times.
✓ Branch 2 taken 31950635 times.
✓ Branch 3 taken 2165191 times.
✓ Branch 4 taken 31948754 times.
✓ Branch 5 taken 7196632 times.
71095995 if (mysql_bin_log.is_open() && (variables.option_bits & OPTION_BIN_LOG) &&
10299
2/2
✓ Branch 0 taken 1940007 times.
✓ Branch 1 taken 30010628 times.
31950635 !(variables.binlog_format == BINLOG_FORMAT_STMT &&
10300
3/4
✓ Branch 0 taken 1939980 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1938090 times.
✓ Branch 3 taken 1890 times.
1940007 !binlog_filter->db_ok(m_db.str))) {
10301 /*
10302 Compute one bit field with the union of all the engine
10303 capabilities, and one with the intersection of all the engine
10304 capabilities.
10305 */
10306 31948754 handler::Table_flags flags_write_some_set = 0;
10307 31948754 handler::Table_flags flags_access_some_set = 0;
10308 31948754 handler::Table_flags flags_write_all_set =
10309 HA_BINLOG_ROW_CAPABLE | HA_BINLOG_STMT_CAPABLE;
10310
10311 /*
10312 If different types of engines are about to be updated.
10313 For example: Innodb and Falcon; Innodb and MyIsam.
10314 */
10315 31948754 bool multi_write_engine = false;
10316 /*
10317 If different types of engines are about to be accessed
10318 and any of them is about to be updated. For example:
10319 Innodb and Falcon; Innodb and MyIsam.
10320 */
10321 31948754 bool multi_access_engine = false;
10322 /*
10323 Track if statement creates or drops a temporary table
10324 and log in ROW if it does.
10325 */
10326 31948754 bool is_create_drop_temp_table = false;
10327 /*
10328 Identifies if a table is changed.
10329 */
10330 31948754 bool is_write = false;
10331 /*
10332 A pointer to a previous table that was changed.
10333 */
10334 31948754 TABLE *prev_write_table = nullptr;
10335 /*
10336 A pointer to a previous table that was accessed.
10337 */
10338 31948754 TABLE *prev_access_table = nullptr;
10339 /*
10340 True if at least one table is transactional.
10341 */
10342 31948754 bool write_to_some_transactional_table = false;
10343 /*
10344 True if at least one table is non-transactional.
10345 */
10346 31948754 bool write_to_some_non_transactional_table = false;
10347 /*
10348 True if all non-transactional tables that has been updated
10349 are temporary.
10350 */
10351 31948754 bool write_all_non_transactional_are_tmp_tables = true;
10352 /**
10353 The number of tables used in the current statement,
10354 that should be replicated.
10355 */
10356 31948754 uint replicated_tables_count = 0;
10357 /**
10358 The number of tables written to in the current statement,
10359 that should not be replicated.
10360 A table should not be replicated when it is considered
10361 'local' to a MySQL instance.
10362 Currently, these tables are:
10363 - mysql.slow_log
10364 - mysql.general_log
10365 - mysql.slave_relay_log_info
10366 - mysql.slave_master_info
10367 - mysql.slave_worker_info
10368 - performance_schema.*
10369 - TODO: information_schema.*
10370 In practice, from this list, only performance_schema.* tables
10371 are written to by user queries.
10372 */
10373 31948754 uint non_replicated_tables_count = 0;
10374 /**
10375 Indicate whether we already reported a warning
10376 on modifying gtid_executed table.
10377 */
10378 31948754 int warned_gtid_executed_table = 0;
10379 #ifndef NDEBUG
10380 {
10381
6/10
✓ Branch 0 taken 31948746 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 31948824 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 144 times.
✓ Branch 5 taken 31948680 times.
✓ Branch 6 taken 144 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 144 times.
✗ Branch 9 not taken.
31948754 DBUG_PRINT("debug", ("prelocked_mode: %s",
10382 get_locked_tables_mode_name(locked_tables_mode)));
10383 }
10384 #endif
10385
10386
4/4
✓ Branch 0 taken 3715232 times.
✓ Branch 1 taken 28233592 times.
✓ Branch 2 taken 850136 times.
✓ Branch 3 taken 2865096 times.
31948824 if (variables.binlog_format != BINLOG_FORMAT_ROW && tables) {
10387 /*
10388 DML statements that modify a table with an auto_increment column based
10389 on rows selected from a table are unsafe as the order in which the rows
10390 are fetched from the select tables cannot be determined and may differ
10391 on master and slave.
10392 */
10393
2/2
✓ Branch 0 taken 406 times.
✓ Branch 1 taken 849724 times.
850136 if (has_write_table_with_auto_increment_and_query_block(tables))
10394
1/2
✓ Branch 0 taken 406 times.
✗ Branch 1 not taken.
406 lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_WRITE_AUTOINC_SELECT);
10395
10396
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 850100 times.
850130 if (has_write_table_auto_increment_not_first_in_pk(tables))
10397
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_AUTOINC_NOT_FIRST);
10398
10399 /*
10400 A query that modifies autoinc column in sub-statement can make the
10401 master and slave inconsistent.
10402 We can solve these problems in mixed mode by switching to binlogging
10403 if at least one updated table is used by sub-statement
10404 */
10405
6/6
✓ Branch 0 taken 9314 times.
✓ Branch 1 taken 840823 times.
✓ Branch 2 taken 289 times.
✓ Branch 3 taken 9031 times.
✓ Branch 4 taken 289 times.
✓ Branch 5 taken 849854 times.
859432 if (lex->requires_prelocking() &&
10406 9314 has_write_table_with_auto_increment(lex->first_not_own_table()))
10407
1/2
✓ Branch 0 taken 289 times.
✗ Branch 1 not taken.
289 lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_AUTOINC_COLUMNS);
10408
10409 /*
10410 A query that modifies a table with a non-deterministic column default
10411 expression in a substatement, can make the master and the slave
10412 inconsistent. Switch to row logging in mixed mode, and raise a warning
10413 in statement mode.
10414 */
10415
4/4
✓ Branch 0 taken 9314 times.
✓ Branch 1 taken 840736 times.
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 849890 times.
859310 if (lex->requires_prelocking() &&
10416
3/4
✓ Branch 0 taken 9167 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 9154 times.
9314 has_write_table_with_nondeterministic_default(
10417 9314 lex->first_not_own_table()))
10418
1/2
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
13 lex->set_stmt_unsafe(
10419 LEX::BINLOG_STMT_UNSAFE_DEFAULT_EXPRESSION_IN_SUBSTATEMENT);
10420
10421 /*
10422 A DML or DDL statement is unsafe if it reads a ACL table while
10423 modifying the table, because SE skips acquiring row locks.
10424 Therefore rows seen by DML or DDL may not have same effect on slave.
10425
10426 We skip checking the same under lock tables mode, because we do
10427 not skip row locks on ACL table in this mode.
10428 */
10429
3/4
✓ Branch 0 taken 850105 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 868 times.
✓ Branch 3 taken 849237 times.
849903 if (has_acl_table_read(this, tables)) {
10430
1/2
✓ Branch 0 taken 285 times.
✗ Branch 1 not taken.
868 lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_ACL_TABLE_READ_IN_DML_DDL);
10431 }
10432 }
10433
10434 /*
10435 Get the capabilities vector for all involved storage engines and
10436 mask out the flags for the binary log.
10437 */
10438
2/2
✓ Branch 0 taken 17315520 times.
✓ Branch 1 taken 31949366 times.
49264886 for (TABLE_LIST *table = tables; table; table = table->next_global) {
10439
2/2
✓ Branch 0 taken 1186949 times.
✓ Branch 1 taken 16129547 times.
17315520 if (table->is_placeholder()) {
10440 /*
10441 Detect if this is a CREATE TEMPORARY or DROP of a
10442 temporary table. This will be used later in determining whether to
10443 log in ROW or STMT if MIXED replication is being used.
10444 */
10445
6/6
✓ Branch 0 taken 1186945 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 825702 times.
✓ Branch 3 taken 361243 times.
✓ Branch 4 taken 8417 times.
✓ Branch 5 taken 1178533 times.
2012652 if (!is_create_drop_temp_table && !table->table &&
10446
2/2
✓ Branch 0 taken 115724 times.
✓ Branch 1 taken 709978 times.
825702 ((lex->sql_command == SQLCOM_CREATE_TABLE &&
10447
2/2
✓ Branch 0 taken 107311 times.
✓ Branch 1 taken 8413 times.
115724 (lex->create_info->options & HA_LEX_CREATE_TMP_TABLE)) ||
10448
2/2
✓ Branch 0 taken 693219 times.
✓ Branch 1 taken 124070 times.
817289 ((lex->sql_command == SQLCOM_DROP_TABLE ||
10449
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 693221 times.
693219 lex->sql_command == SQLCOM_TRUNCATE) &&
10450
3/4
✓ Branch 0 taken 124069 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 124065 times.
124068 find_temporary_table(this, table)))) {
10451 8417 is_create_drop_temp_table = true;
10452 }
10453 1186950 continue;
10454 }
10455 16129547 handler::Table_flags const flags = table->table->file->ha_table_flags();
10456
10457
5/8
✓ Branch 0 taken 16129211 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 16129565 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 373 times.
✓ Branch 5 taken 16129192 times.
✓ Branch 6 taken 373 times.
✗ Branch 7 not taken.
16128383 DBUG_PRINT("info", ("table: %s; ha_table_flags: 0x%llx",
10458 table->table_name, flags));
10459
10460
2/2
✓ Branch 0 taken 895363 times.
✓ Branch 1 taken 15234202 times.
16129565 if (table->table->no_replicate) {
10461
1/2
✓ Branch 0 taken 895363 times.
✗ Branch 1 not taken.
895363 if (!warned_gtid_executed_table) {
10462 warned_gtid_executed_table =
10463
1/2
✓ Branch 0 taken 895363 times.
✗ Branch 1 not taken.
895363 gtid_state->warn_or_err_on_modify_gtid_table(this, table);
10464 /*
10465 Do not allow users to modify the gtid_executed table
10466 explicitly by a XA transaction.
10467 */
10468
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 895360 times.
895363 if (warned_gtid_executed_table == 2) return -1;
10469 }
10470 /*
10471 The statement uses a table that is not replicated.
10472 The following properties about the table:
10473 - persistent / transient
10474 - transactional / non transactional
10475 - temporary / permanent
10476 - read or write
10477 - multiple engines involved because of this table
10478 are not relevant, as this table is completely ignored.
10479 Because the statement uses a non replicated table,
10480 using STATEMENT format in the binlog is impossible.
10481 Either this statement will be discarded entirely,
10482 or it will be logged (possibly partially) in ROW format.
10483 */
10484
1/2
✓ Branch 0 taken 895360 times.
✗ Branch 1 not taken.
895360 lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_TABLE);
10485
10486
2/2
✓ Branch 0 taken 7924 times.
✓ Branch 1 taken 887436 times.
895360 if (table->lock_descriptor().type >= TL_WRITE_ALLOW_WRITE) {
10487 7924 non_replicated_tables_count++;
10488 7924 continue;
10489 }
10490 }
10491
10492 16121638 replicated_tables_count++;
10493
10494 16121638 bool trans = table->table->file->has_transactions();
10495
10496
2/2
✓ Branch 0 taken 11256041 times.
✓ Branch 1 taken 4865628 times.
16121584 if (table->lock_descriptor().type >= TL_WRITE_ALLOW_WRITE) {
10497 11256041 write_to_some_transactional_table =
10498
4/4
✓ Branch 0 taken 10936594 times.
✓ Branch 1 taken 319447 times.
✓ Branch 2 taken 10542167 times.
✓ Branch 3 taken 394427 times.
11256041 write_to_some_transactional_table || trans;
10499
10500 11256041 write_to_some_non_transactional_table =
10501
4/4
✓ Branch 0 taken 11248782 times.
✓ Branch 1 taken 7259 times.
✓ Branch 2 taken 389925 times.
✓ Branch 3 taken 10858857 times.
11256041 write_to_some_non_transactional_table || !trans;
10502
10503
2/2
✓ Branch 0 taken 326057 times.
✓ Branch 1 taken 10929984 times.
11256041 if (prev_write_table &&
10504
2/2
✓ Branch 0 taken 3576 times.
✓ Branch 1 taken 322481 times.
326057 prev_write_table->file->ht != table->table->file->ht)
10505 3576 multi_write_engine = true;
10506
10507
2/2
✓ Branch 0 taken 96763 times.
✓ Branch 1 taken 11159278 times.
11256041 if (table->table->s->tmp_table)
10508
3/4
✓ Branch 0 taken 95258 times.
✓ Branch 1 taken 1505 times.
✓ Branch 2 taken 96763 times.
✗ Branch 3 not taken.
96763 lex->set_stmt_accessed_table(
10509 trans ? LEX::STMT_WRITES_TEMP_TRANS_TABLE
10510 : LEX::STMT_WRITES_TEMP_NON_TRANS_TABLE);
10511 else
10512
3/4
✓ Branch 0 taken 10764505 times.
✓ Branch 1 taken 394773 times.
✓ Branch 2 taken 11159436 times.
✗ Branch 3 not taken.
11159278 lex->set_stmt_accessed_table(trans
10513 ? LEX::STMT_WRITES_TRANS_TABLE
10514 : LEX::STMT_WRITES_NON_TRANS_TABLE);
10515
10516 /*
10517 Non-transactional updates are allowed when row binlog format is
10518 used and all non-transactional tables are temporary.
10519 Binlog format is checked on THD::is_dml_gtid_compatible() method.
10520 */
10521
2/2
✓ Branch 0 taken 395800 times.
✓ Branch 1 taken 10860399 times.
11256199 if (!trans)
10522 395800 write_all_non_transactional_are_tmp_tables =
10523
2/2
✓ Branch 0 taken 390125 times.
✓ Branch 1 taken 5675 times.
785925 write_all_non_transactional_are_tmp_tables &&
10524
2/2
✓ Branch 0 taken 1501 times.
✓ Branch 1 taken 388624 times.
390125 table->table->s->tmp_table;
10525
10526 11256199 flags_write_all_set &= flags;
10527 11256199 flags_write_some_set |= flags;
10528 11256199 is_write = true;
10529
10530 11256199 prev_write_table = table->table;
10531
10532 /*
10533 It should be marked unsafe if a table which uses a fulltext parser
10534 plugin is modified. See also bug#48183.
10535 */
10536
1/2
✓ Branch 0 taken 11255016 times.
✗ Branch 1 not taken.
11256199 if (!lex->is_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_FULLTEXT_PLUGIN)) {
10537
2/2
✓ Branch 0 taken 168 times.
✓ Branch 1 taken 11255327 times.
11255016 if (fulltext_unsafe_set(table->table->s))
10538
1/2
✓ Branch 0 taken 168 times.
✗ Branch 1 not taken.
168 lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_FULLTEXT_PLUGIN);
10539 }
10540 /*
10541 INSERT...ON DUPLICATE KEY UPDATE on a table with more than one unique
10542 keys can be unsafe. Check for it if the flag is already not marked for
10543 the given statement.
10544 */
10545 11255455 if (!lex->is_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_INSERT_TWO_KEYS) &&
10546
6/6
✓ Branch 0 taken 11255850 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 10136982 times.
✓ Branch 3 taken 1118868 times.
✓ Branch 4 taken 82104 times.
✓ Branch 5 taken 11173749 times.
21392835 lex->sql_command == SQLCOM_INSERT &&
10547
2/2
✓ Branch 0 taken 82104 times.
✓ Branch 1 taken 10054878 times.
10136982 lex->duplicates == DUP_UPDATE) {
10548 82104 uint keys = table->table->s->keys, i = 0, unique_keys = 0;
10549 82104 for (KEY *keyinfo = table->table->s->key_info;
10550
4/4
✓ Branch 0 taken 85169 times.
✓ Branch 1 taken 82095 times.
✓ Branch 2 taken 85160 times.
✓ Branch 3 taken 9 times.
167264 i < keys && unique_keys <= 1; i++, keyinfo++) {
10551
2/2
✓ Branch 0 taken 82383 times.
✓ Branch 1 taken 2777 times.
85160 if (keyinfo->flags & HA_NOSAME) unique_keys++;
10552 }
10553
2/2
✓ Branch 0 taken 308 times.
✓ Branch 1 taken 81796 times.
82104 if (unique_keys > 1)
10554
1/2
✓ Branch 0 taken 308 times.
✗ Branch 1 not taken.
308 lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_INSERT_TWO_KEYS);
10555 }
10556 }
10557
2/2
✓ Branch 0 taken 2684 times.
✓ Branch 1 taken 16118183 times.
16121481 if (lex->get_using_match()) {
10558
2/2
✓ Branch 0 taken 1061 times.
✓ Branch 1 taken 1623 times.
2684 if (fulltext_unsafe_set(table->table->s))
10559
1/2
✓ Branch 0 taken 1058 times.
✗ Branch 1 not taken.
1061 lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_FULLTEXT_PLUGIN);
10560 }
10561
10562 16120833 flags_access_some_set |= flags;
10563
10564
4/4
✓ Branch 0 taken 23904 times.
✓ Branch 1 taken 16096929 times.
✓ Branch 2 taken 16113197 times.
✓ Branch 3 taken 7636 times.
16144737 if (lex->sql_command != SQLCOM_CREATE_TABLE ||
10565
1/2
✓ Branch 0 taken 23904 times.
✗ Branch 1 not taken.
23904 (lex->sql_command == SQLCOM_CREATE_TABLE &&
10566
2/2
✓ Branch 0 taken 21544 times.
✓ Branch 1 taken 2360 times.
23904 ((lex->create_info->options & HA_LEX_CREATE_TMP_TABLE) ||
10567
2/2
✓ Branch 0 taken 13732 times.
✓ Branch 1 taken 7812 times.
21544 (table->lock_descriptor().type < TL_WRITE_ALLOW_WRITE)))) {
10568
2/2
✓ Branch 0 taken 111726 times.
✓ Branch 1 taken 16001471 times.
16113197 if (table->table->s->tmp_table)
10569
3/4
✓ Branch 0 taken 106718 times.
✓ Branch 1 taken 5008 times.
✓ Branch 2 taken 111727 times.
✗ Branch 3 not taken.
111726 lex->set_stmt_accessed_table(
10570 trans ? LEX::STMT_READS_TEMP_TRANS_TABLE
10571 : LEX::STMT_READS_TEMP_NON_TRANS_TABLE);
10572 else
10573
3/4
✓ Branch 0 taken 14945578 times.
✓ Branch 1 taken 1055893 times.
✓ Branch 2 taken 16002503 times.
✗ Branch 3 not taken.
16001471 lex->set_stmt_accessed_table(trans ? LEX::STMT_READS_TRANS_TABLE
10574 : LEX::STMT_READS_NON_TRANS_TABLE);
10575 }
10576
10577
2/2
✓ Branch 0 taken 2713200 times.
✓ Branch 1 taken 13408666 times.
16121866 if (prev_access_table &&
10578
2/2
✓ Branch 0 taken 12003 times.
✓ Branch 1 taken 2701197 times.
2713200 prev_access_table->file->ht != table->table->file->ht)
10579 12003 multi_access_engine = true;
10580
10581 16121866 prev_access_table = table->table;
10582 }
10583
5/6
✓ Branch 0 taken 10930123 times.
✓ Branch 1 taken 21019243 times.
✓ Branch 2 taken 387849 times.
✓ Branch 3 taken 10542274 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 387849 times.
31949366 assert(!is_write || write_to_some_transactional_table ||
10584 write_to_some_non_transactional_table);
10585 /*
10586 write_all_non_transactional_are_tmp_tables may be true if any
10587 non-transactional table was not updated, so we fix its value here.
10588 */
10589 31949366 write_all_non_transactional_are_tmp_tables =
10590
4/4
✓ Branch 0 taken 31559687 times.
✓ Branch 1 taken 389679 times.
✓ Branch 2 taken 1329 times.
✓ Branch 3 taken 31558358 times.
31949366 write_all_non_transactional_are_tmp_tables &&
10591 write_to_some_non_transactional_table;
10592
10593
5/8
✓ Branch 0 taken 31948701 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 31948744 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 148 times.
✓ Branch 5 taken 31948596 times.
✓ Branch 6 taken 148 times.
✗ Branch 7 not taken.
31949366 DBUG_PRINT("info", ("flags_write_all_set: 0x%llx", flags_write_all_set));
10594
5/8
✓ Branch 0 taken 31948783 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 31948851 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 148 times.
✓ Branch 5 taken 31948703 times.
✓ Branch 6 taken 148 times.
✗ Branch 7 not taken.
31948744 DBUG_PRINT("info", ("flags_write_some_set: 0x%llx", flags_write_some_set));
10595
5/8
✓ Branch 0 taken 31948781 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 31948899 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 148 times.
✓ Branch 5 taken 31948751 times.
✓ Branch 6 taken 148 times.
✗ Branch 7 not taken.
31948851 DBUG_PRINT("info",
10596 ("flags_access_some_set: 0x%llx", flags_access_some_set));
10597
5/8
✓ Branch 0 taken 31948803 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 31948881 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 148 times.
✓ Branch 5 taken 31948733 times.
✓ Branch 6 taken 148 times.
✗ Branch 7 not taken.
31948899 DBUG_PRINT("info", ("multi_write_engine: %d", multi_write_engine));
10598
4/8
✓ Branch 0 taken 31948750 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 31948885 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 148 times.
✓ Branch 5 taken 31948737 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
31948881 DBUG_PRINT("info", ("multi_access_engine: %d", multi_access_engine));
10599
10600 31948569 int error = 0;
10601 int unsafe_flags;
10602
10603 /*
10604 With transactional data dictionary, CREATE TABLE runs as one statement
10605 in a multi-statement transaction internally. Revert this for the
10606 purposes of determining mixed statement safety.
10607 */
10608
4/4
✓ Branch 0 taken 31814196 times.
✓ Branch 1 taken 134373 times.
✓ Branch 2 taken 11684900 times.
✓ Branch 3 taken 20129108 times.
63762577 const bool multi_stmt_trans = lex->sql_command != SQLCOM_CREATE_TABLE &&
10609 31814196 in_multi_stmt_transaction_mode();
10610
1/2
✓ Branch 0 taken 31948757 times.
✗ Branch 1 not taken.
31948381 bool trans_table = trans_has_updated_trans_table(this);
10611 31948757 bool binlog_direct = variables.binlog_direct_non_trans_update;
10612
10613
2/2
✓ Branch 0 taken 1347 times.
✓ Branch 1 taken 31947650 times.
31948997 if (lex->is_mixed_stmt_unsafe(multi_stmt_trans, binlog_direct, trans_table,
10614
1/2
✓ Branch 0 taken 31948997 times.
✗ Branch 1 not taken.
31948757 tx_isolation))
10615
1/2
✓ Branch 0 taken 1347 times.
✗ Branch 1 not taken.
1347 lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_MIXED_STATEMENT);
10616
8/8
✓ Branch 0 taken 11683690 times.
✓ Branch 1 taken 20263960 times.
✓ Branch 2 taken 10791198 times.
✓ Branch 3 taken 892492 times.
✓ Branch 4 taken 10753800 times.
✓ Branch 5 taken 37398 times.
✓ Branch 6 taken 1347 times.
✓ Branch 7 taken 31946303 times.
42701450 else if (multi_stmt_trans && trans_table && !binlog_direct &&
10617
3/4
✓ Branch 0 taken 10753800 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1347 times.
✓ Branch 3 taken 10752453 times.
10753800 lex->stmt_accessed_table(LEX::STMT_WRITES_NON_TRANS_TABLE))
10618
1/2
✓ Branch 0 taken 1347 times.
✗ Branch 1 not taken.
1347 lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_NONTRANS_AFTER_TRANS);
10619
10620 /*
10621 If more than one engine is involved in the statement and at
10622 least one is doing it's own logging (is *self-logging*), the
10623 statement cannot be logged atomically, so we generate an error
10624 rather than allowing the binlog to become corrupt.
10625 */
10626
3/4
✓ Branch 0 taken 3439 times.
✓ Branch 1 taken 31945558 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3439 times.
31948997 if (multi_write_engine && (flags_write_some_set & HA_HAS_OWN_BINLOGGING))
10627 my_error((error = ER_BINLOG_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE),
10628 MYF(0));
10629
2/2
✓ Branch 0 taken 11188 times.
✓ Branch 1 taken 31937809 times.
31948997 else if (multi_access_engine &&
10630
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11188 times.
11188 flags_access_some_set & HA_HAS_OWN_BINLOGGING)
10631 lex->set_stmt_unsafe(
10632 LEX::BINLOG_STMT_UNSAFE_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE);
10633
10634 /* XA is unsafe for statements */
10635
4/4
✓ Branch 0 taken 10929838 times.
✓ Branch 1 taken 21018338 times.
✓ Branch 2 taken 1031 times.
✓ Branch 3 taken 31947088 times.
42877957 if (is_write &&
10636
2/2
✓ Branch 0 taken 1031 times.
✓ Branch 1 taken 10928750 times.
10929838 !get_transaction()->xid_state()->has_state(XID_STATE::XA_NOTR))
10637
1/2
✓ Branch 0 taken 1031 times.
✗ Branch 1 not taken.
1031 lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_XA);
10638
10639
3/4
✓ Branch 0 taken 31948265 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6030 times.
✓ Branch 3 taken 31942235 times.
31948119 DBUG_EXECUTE_IF("make_stmt_only_engines",
10640 { flags_write_all_set = HA_BINLOG_STMT_CAPABLE; };);
10641
10642 /* both statement-only and row-only engines involved */
10643
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 31948265 times.
31948265 if ((flags_write_all_set &
10644 (HA_BINLOG_STMT_CAPABLE | HA_BINLOG_ROW_CAPABLE)) == 0) {
10645 /*
10646 1. Error: Binary logging impossible since both row-incapable
10647 engines and statement-incapable engines are involved
10648 */
10649 my_error((error = ER_BINLOG_ROW_ENGINE_AND_STMT_ENGINE), MYF(0));
10650 }
10651 /* statement-only engines involved */
10652
2/2
✓ Branch 0 taken 6036 times.
✓ Branch 1 taken 31942229 times.
31948265 else if ((flags_write_all_set & HA_BINLOG_ROW_CAPABLE) == 0) {
10653
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6036 times.
6036 if (lex->is_stmt_row_injection()) {
10654 /*
10655 4. Error: Cannot execute row injection since table uses
10656 storage engine limited to statement-logging
10657 */
10658 my_error((error = ER_BINLOG_ROW_INJECTION_AND_STMT_ENGINE), MYF(0));
10659
4/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 6033 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 6033 times.
6039 } else if (variables.binlog_format == BINLOG_FORMAT_ROW &&
10660
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
3 sqlcom_can_generate_row_events(this->lex->sql_command)) {
10661 /*
10662 2. Error: Cannot modify table that uses a storage engine
10663 limited to statement-logging when BINLOG_FORMAT = ROW
10664 */
10665
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 my_error((error = ER_BINLOG_ROW_MODE_AND_STMT_ENGINE), MYF(0));
10666
4/4
✓ Branch 0 taken 581 times.
✓ Branch 1 taken 5452 times.
✓ Branch 2 taken 177 times.
✓ Branch 3 taken 5856 times.
6614 } else if (variables.binlog_format == BINLOG_FORMAT_MIXED &&
10667
3/4
✓ Branch 0 taken 581 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 177 times.
✓ Branch 3 taken 404 times.
581 ((unsafe_flags = lex->get_stmt_unsafe_flags()) != 0)) {
10668 /*
10669 3. Error: Cannot execute statement: binlogging of unsafe
10670 statement is impossible when storage engine is limited to
10671 statement-logging and BINLOG_FORMAT = MIXED.
10672 */
10673
2/2
✓ Branch 0 taken 4602 times.
✓ Branch 1 taken 177 times.
4779 for (int unsafe_type = 0; unsafe_type < LEX::BINLOG_STMT_UNSAFE_COUNT;
10674 unsafe_type++)
10675
2/2
✓ Branch 0 taken 201 times.
✓ Branch 1 taken 4401 times.
4602 if (unsafe_flags & (1 << unsafe_type))
10676
1/2
✓ Branch 0 taken 201 times.
✗ Branch 1 not taken.
201 my_error(
10677 (error = ER_BINLOG_UNSAFE_AND_STMT_ENGINE), MYF(0),
10678
1/2
✓ Branch 0 taken 201 times.
✗ Branch 1 not taken.
201 ER_THD_NONCONST(current_thd,
10679
1/2
✓ Branch 0 taken 201 times.
✗ Branch 1 not taken.
201 LEX::binlog_stmt_unsafe_errcode[unsafe_type]));
10680
4/4
✓ Branch 0 taken 342 times.
✓ Branch 1 taken 5514 times.
✓ Branch 2 taken 188 times.
✓ Branch 3 taken 5668 times.
6198 } else if (is_write &&
10681
3/4
✓ Branch 0 taken 342 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 188 times.
✓ Branch 3 taken 154 times.
342 ((unsafe_flags = lex->get_stmt_unsafe_flags()) != 0)) {
10682 /*
10683 7. Warning: Unsafe statement logged as statement due to
10684 binlog_format = STATEMENT
10685 */
10686 188 binlog_unsafe_warning_flags |= unsafe_flags;
10687
3/12
✓ Branch 0 taken 188 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 188 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 188 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
188 DBUG_PRINT("info", ("Scheduling warning to be issued by "
10688 "binlog_query: '%s'",
10689 ER_THD(current_thd, ER_BINLOG_UNSAFE_STATEMENT)));
10690
3/8
✓ Branch 0 taken 188 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 188 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 188 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
188 DBUG_PRINT("info", ("binlog_unsafe_warning_flags: 0x%x",
10691 binlog_unsafe_warning_flags));
10692 }
10693 /* log in statement format! */
10694 }
10695 /* no statement-only engines */
10696 else {
10697 /* binlog_format = STATEMENT */
10698
2/2
✓ Branch 0 taken 1932354 times.
✓ Branch 1 taken 30009875 times.
31942229 if (variables.binlog_format == BINLOG_FORMAT_STMT) {
10699
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1932548 times.
1932354 if (lex->is_stmt_row_injection()) {
10700 /*
10701 6. Error: Cannot execute row injection since
10702 BINLOG_FORMAT = STATEMENT
10703 */
10704
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
1 my_error((error = ER_BINLOG_ROW_INJECTION_AND_STMT_MODE), MYF(0));
10705
3/4
✓ Branch 0 taken 864 times.
✓ Branch 1 taken 1931684 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1932548 times.
1933412 } else if ((flags_write_all_set & HA_BINLOG_STMT_CAPABLE) == 0 &&
10706
2/4
✓ Branch 0 taken 864 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 864 times.
864 sqlcom_can_generate_row_events(this->lex->sql_command)) {
10707 /*
10708 5. Error: Cannot modify table that uses a storage engine
10709 limited to row-logging when binlog_format = STATEMENT
10710 */
10711 my_error((error = ER_BINLOG_STMT_MODE_AND_ROW_ENGINE), MYF(0), "");
10712
4/4
✓ Branch 0 taken 192894 times.
✓ Branch 1 taken 1739654 times.
✓ Branch 2 taken 13053 times.
✓ Branch 3 taken 1919581 times.
2125528 } else if (is_write &&
10713
3/4
✓ Branch 0 taken 192980 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13053 times.
✓ Branch 3 taken 179927 times.
192894 (unsafe_flags = lex->get_stmt_unsafe_flags()) != 0) {
10714 /*
10715 7. Warning: Unsafe statement logged as statement due to
10716 binlog_format = STATEMENT
10717 */
10718 13053 binlog_unsafe_warning_flags |= unsafe_flags;
10719
3/12
✓ Branch 0 taken 13053 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13053 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 13053 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
13053 DBUG_PRINT("info", ("Scheduling warning to be issued by "
10720 "binlog_query: '%s'",
10721 ER_THD(current_thd, ER_BINLOG_UNSAFE_STATEMENT)));
10722
3/8
✓ Branch 0 taken 13053 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13053 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 13053 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
13053 DBUG_PRINT("info", ("binlog_unsafe_warning_flags: 0x%x",
10723 binlog_unsafe_warning_flags));
10724 }
10725 /* log in statement format! */
10726 }
10727 /* No statement-only engines and binlog_format != STATEMENT.
10728 I.e., nothing prevents us from row logging if needed. */
10729 else {
10730
5/6
✓ Branch 0 taken 30009670 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 27129138 times.
✓ Branch 3 taken 286096 times.
✓ Branch 4 taken 27129078 times.
✓ Branch 5 taken 364 times.
84554492 if (lex->is_stmt_unsafe() || lex->is_stmt_row_injection() ||
10731 27129138 lex->is_stmt_unsafe_with_mixed_mode() ||
10732
2/2
✓ Branch 0 taken 27127061 times.
✓ Branch 1 taken 2017 times.
27129078 (flags_write_all_set & HA_BINLOG_STMT_CAPABLE) == 0 ||
10733
3/4
✓ Branch 0 taken 27127226 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 27024656 times.
✓ Branch 3 taken 102570 times.
27127061 lex->stmt_accessed_table(LEX::STMT_READS_TEMP_TRANS_TABLE) ||
10734
9/10
✓ Branch 0 taken 27415175 times.
✓ Branch 1 taken 2594495 times.
✓ Branch 2 taken 27024678 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 27021370 times.
✓ Branch 5 taken 3308 times.
✓ Branch 6 taken 6612 times.
✓ Branch 7 taken 27014758 times.
✓ Branch 8 taken 2995466 times.
✓ Branch 9 taken 27014754 times.
57425373 lex->stmt_accessed_table(LEX::STMT_READS_TEMP_NON_TRANS_TABLE) ||
10735 is_create_drop_temp_table) {
10736 #ifndef NDEBUG
10737
1/2
✓ Branch 0 taken 2995523 times.
✗ Branch 1 not taken.
2995466 int flags = lex->get_stmt_unsafe_flags();
10738
5/8
✓ Branch 0 taken 2995507 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2995473 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 2995468 times.
✓ Branch 6 taken 13 times.
✗ Branch 7 not taken.
2995523 DBUG_PRINT("info", ("setting row format for unsafe statement"));
10739
2/2
✓ Branch 0 taken 77878359 times.
✓ Branch 1 taken 2997411 times.
80875770 for (int i = 0; i < Query_tables_list::BINLOG_STMT_UNSAFE_COUNT;
10740 i++) {
10741
2/2
✓ Branch 0 taken 2625309 times.
✓ Branch 1 taken 75253050 times.
77878359 if (flags & (1 << i))
10742
7/12
✓ Branch 0 taken 2625330 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2625306 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 2625301 times.
✓ Branch 6 taken 5 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 5 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1938 times.
✗ Branch 11 not taken.
2625309 DBUG_PRINT(
10743 "info",
10744 ("unsafe reason: %s",
10745 ER_THD_NONCONST(
10746 current_thd,
10747 Query_tables_list::binlog_stmt_unsafe_errcode[i])));
10748 }
10749
5/8
✓ Branch 0 taken 2995520 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2995518 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 2995513 times.
✓ Branch 6 taken 5 times.
✗ Branch 7 not taken.
2997411 DBUG_PRINT("info",
10750 ("is_row_injection=%d", lex->is_stmt_row_injection()));
10751
5/8
✓ Branch 0 taken 2995517 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2995519 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 2995514 times.
✓ Branch 6 taken 5 times.
✗ Branch 7 not taken.
2995518 DBUG_PRINT("info", ("stmt_capable=%llu",
10752 (flags_write_all_set & HA_BINLOG_STMT_CAPABLE)));
10753
5/8
✓ Branch 0 taken 2995445 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2995508 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 2995503 times.
✓ Branch 6 taken 5 times.
✗ Branch 7 not taken.
2995519 DBUG_PRINT("info", ("lex->is_stmt_unsafe_with_mixed_mode = %d",
10754 lex->is_stmt_unsafe_with_mixed_mode()));
10755 #endif
10756 /* log in row format! */
10757
1/2
✓ Branch 0 taken 2994263 times.
✗ Branch 1 not taken.
2995508 set_current_stmt_binlog_format_row_if_mixed();
10758 }
10759 }
10760 }
10761
10762
2/2
✓ Branch 0 taken 7924 times.
✓ Branch 1 taken 31939763 times.
31947687 if (non_replicated_tables_count > 0) {
10763
4/4
✓ Branch 0 taken 138 times.
✓ Branch 1 taken 7786 times.
✓ Branch 2 taken 118 times.
✓ Branch 3 taken 20 times.
7924 if ((replicated_tables_count == 0) || !is_write) {
10764
3/8
✓ Branch 0 taken 7904 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7904 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 7904 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
7904 DBUG_PRINT("info",
10765 ("decision: no logging, no replicated table affected"));
10766 7904 set_binlog_local_stmt_filter();
10767 } else {
10768
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 12 times.
20 if (!is_current_stmt_binlog_format_row()) {
10769
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 my_error((error = ER_BINLOG_STMT_MODE_AND_NO_REPL_TABLES), MYF(0));
10770 } else {
10771 12 clear_binlog_local_stmt_filter();
10772 }
10773 }
10774 } else {
10775 31939763 clear_binlog_local_stmt_filter();
10776 }
10777
10778
4/4
✓ Branch 0 taken 31947201 times.
✓ Branch 1 taken 199 times.
✓ Branch 2 taken 396 times.
✓ Branch 3 taken 31948505 times.
63896102 if (!error &&
10779
3/4
✓ Branch 0 taken 31948702 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 396 times.
✓ Branch 3 taken 31948306 times.
31947201 !is_dml_gtid_compatible(write_to_some_transactional_table,
10780 write_to_some_non_transactional_table,
10781 write_all_non_transactional_are_tmp_tables))
10782 396 error = 1;
10783
10784
2/2
✓ Branch 0 taken 584 times.
✓ Branch 1 taken 31948317 times.
31948901 if (error) {
10785
3/8
✓ Branch 0 taken 584 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 584 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 584 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
584 DBUG_PRINT("info", ("decision: no logging since an error was generated"));
10786 584 return -1;
10787 }
10788
10789
2/2
✓ Branch 0 taken 10929082 times.
✓ Branch 1 taken 21019235 times.
31948317 if (is_write &&
10790
2/2
✓ Branch 0 taken 10642708 times.
✓ Branch 1 taken 286374 times.
10929082 lex->sql_command != SQLCOM_END /* rows-event applying by slave */) {
10791 /*
10792 Master side of DML in the STMT format events parallelization.
10793 All involving table db:s are stored in a abc-ordered name list.
10794 In case the number of databases exceeds MAX_DBS_IN_EVENT_MTS maximum
10795 the list gathering breaks since it won't be sent to the slave.
10796 */
10797
2/2
✓ Branch 0 taken 11020675 times.
✓ Branch 1 taken 10642155 times.
21662830 for (TABLE_LIST *table = tables; table; table = table->next_global) {
10798
2/2
✓ Branch 0 taken 11976 times.
✓ Branch 1 taken 11009521 times.
11020675 if (table->is_placeholder()) continue;
10799
10800
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11009521 times.
11009521 assert(table->table);
10801
10802
2/2
✓ Branch 0 taken 995 times.
✓ Branch 1 taken 11007440 times.
11009521 if (table->table->s->is_referenced_by_foreign_key()) {
10803 /*
10804 FK-referenced dbs can't be gathered currently. The following
10805 event will be marked for sequential execution on slave.
10806 */
10807 995 binlog_accessed_db_names = nullptr;
10808
1/2
✓ Branch 0 taken 995 times.
✗ Branch 1 not taken.
995 add_to_binlog_accessed_dbs("");
10809 995 break;
10810 }
10811
2/2
✓ Branch 0 taken 589996 times.
✓ Branch 1 taken 10417956 times.
11007440 if (!is_current_stmt_binlog_format_row())
10812
1/2
✓ Branch 0 taken 590190 times.
✗ Branch 1 not taken.
589996 add_to_binlog_accessed_dbs(table->db);
10813 }
10814 }
10815
7/10
✓ Branch 0 taken 31947545 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 31948073 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 148 times.
✓ Branch 5 taken 31947925 times.
✓ Branch 6 taken 114 times.
✓ Branch 7 taken 34 times.
✓ Branch 8 taken 148 times.
✗ Branch 9 not taken.
31948759 DBUG_PRINT("info",
10816 ("decision: logging in %s format",
10817 is_current_stmt_binlog_format_row() ? "ROW" : "STATEMENT"));
10818
10819
2/2
✓ Branch 0 taken 28233244 times.
✓ Branch 1 taken 3714829 times.
31948073 if (variables.binlog_format == BINLOG_FORMAT_ROW &&
10820
2/2
✓ Branch 0 taken 27862964 times.
✓ Branch 1 taken 370280 times.
28233244 (lex->sql_command == SQLCOM_UPDATE ||
10821
2/2
✓ Branch 0 taken 27860986 times.
✓ Branch 1 taken 1978 times.
27862964 lex->sql_command == SQLCOM_UPDATE_MULTI ||
10822
2/2
✓ Branch 0 taken 27806574 times.
✓ Branch 1 taken 54412 times.
27860986 lex->sql_command == SQLCOM_DELETE ||
10823
2/2
✓ Branch 0 taken 677 times.
✓ Branch 1 taken 27805897 times.
27806574 lex->sql_command == SQLCOM_DELETE_MULTI)) {
10824 427347 String table_names;
10825 /*
10826 Generate a warning for UPDATE/DELETE statements that modify a
10827 BLACKHOLE table, as row events are not logged in row format.
10828 */
10829
2/2
✓ Branch 0 taken 443649 times.
✓ Branch 1 taken 427507 times.
871156 for (TABLE_LIST *table = tables; table; table = table->next_global) {
10830
2/2
✓ Branch 0 taken 8400 times.
✓ Branch 1 taken 435279 times.
443649 if (table->is_placeholder()) continue;
10831
4/4
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 435265 times.
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 435265 times.
435293 if (table->table->file->ht->db_type == DB_TYPE_BLACKHOLE_DB &&
10832
1/2
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
14 table->lock_descriptor().type >= TL_WRITE_ALLOW_WRITE) {
10833
1/2
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
14 table_names.append(table->table_name);
10834
1/2
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
14 table_names.append(",");
10835 }
10836 }
10837
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 427429 times.
427507 if (!table_names.is_empty()) {
10838
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 6 times.
22 bool is_update = (lex->sql_command == SQLCOM_UPDATE ||
10839
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 7 times.
8 lex->sql_command == SQLCOM_UPDATE_MULTI);
10840 /*
10841 Replace the last ',' with '.' for table_names
10842 */
10843
1/2
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
14 table_names.replace(table_names.length() - 1, 1, ".", 1);
10844
5/8
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 7 times.
✓ Branch 4 taken 14 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 14 times.
✗ Branch 7 not taken.
14 push_warning_printf(
10845 this, Sql_condition::SL_WARNING, WARN_ON_BLOCKHOLE_IN_RBR,
10846 ER_THD(this, WARN_ON_BLOCKHOLE_IN_RBR),
10847 is_update ? "UPDATE" : "DELETE", table_names.c_ptr());
10848 }
10849 427443 }
10850 } else {
10851
6/10
✓ Branch 0 taken 7196583 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7196661 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 7196658 times.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
7196632 DBUG_PRINT(
10852 "info",
10853 ("decision: no logging since "
10854 "mysql_bin_log.is_open() = %d "
10855 "and (options & OPTION_BIN_LOG) = 0x%llx "
10856 "and binlog_format = %lu "
10857 "and binlog_filter->db_ok(db) = %d",
10858 mysql_bin_log.is_open(), (variables.option_bits & OPTION_BIN_LOG),
10859 variables.binlog_format, binlog_filter->db_ok(m_db.str)));
10860
10861
2/2
✓ Branch 0 taken 6447066 times.
✓ Branch 1 taken 7196678 times.
13643744 for (TABLE_LIST *table = tables; table; table = table->next_global) {
10862
6/6
✓ Branch 0 taken 5852394 times.
✓ Branch 1 taken 594684 times.
✓ Branch 2 taken 1048355 times.
✓ Branch 3 taken 4804039 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 6447084 times.
7495428 if (!table->is_placeholder() && table->table->no_replicate &&
10863
3/4
✓ Branch 0 taken 1048362 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1048361 times.
1048355 gtid_state->warn_or_err_on_modify_gtid_table(this, table))
10864 1 break;
10865 }
10866 }
10867
10868 #if defined(ENABLED_DEBUG_SYNC)
10869
3/4
✓ Branch 0 taken 39143620 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 39093413 times.
✓ Branch 3 taken 50207 times.
39144846 if (!is_attachable_ro_transaction_active())
10870
3/4
✓ Branch 0 taken 36291635 times.
✓ Branch 1 taken 2801590 times.
✓ Branch 2 taken 36293225 times.
✗ Branch 3 not taken.
39093413 DEBUG_SYNC(this, "end_decide_logging_format");
10871 #endif
10872
10873 39145022 return 0;
10874 39145609 }
10875
10876 /**
10877 Given that a possible violation of gtid consistency has happened,
10878 checks if gtid-inconsistencies are forbidden by the current value of
10879 ENFORCE_GTID_CONSISTENCY and GTID_MODE. If forbidden, generates
10880 error or warning accordingly.
10881
10882 @param thd The thread that has issued the GTID-violating statement.
10883
10884 @param error_code The error code to use, if error or warning is to
10885 be generated.
10886
10887 @param log_error_code The error code to use, if error message is to
10888 be logged.
10889
10890 @retval false Error was generated.
10891 @retval true No error was generated (possibly a warning was generated).
10892 */
10893 6943 static bool handle_gtid_consistency_violation(THD *thd, int error_code,
10894 int log_error_code) {
10895
1/2
✓ Branch 0 taken 6943 times.
✗ Branch 1 not taken.
6943 DBUG_TRACE;
10896
10897 6943 enum_gtid_type gtid_next_type = thd->variables.gtid_next.type;
10898
1/2
✓ Branch 0 taken 6943 times.
✗ Branch 1 not taken.
6943 global_sid_lock->rdlock();
10899 enum_gtid_consistency_mode gtid_consistency_mode =
10900
1/2
✓ Branch 0 taken 6943 times.
✗ Branch 1 not taken.
6943 get_gtid_consistency_mode();
10901
1/2
✓ Branch 0 taken 6943 times.
✗ Branch 1 not taken.
6943 auto gtid_mode = global_gtid_mode.get();
10902
10903
7/12
✓ Branch 0 taken 6943 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6943 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 6937 times.
✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 6 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 6 times.
✗ Branch 11 not taken.
6943 DBUG_PRINT("info", ("gtid_next.type=%d gtid_mode=%s "
10904 "gtid_consistency_mode=%d error=%d query=%s",
10905 gtid_next_type, Gtid_mode::to_string(gtid_mode),
10906 gtid_consistency_mode, error_code, thd->query().str));
10907
10908 /*
10909 GTID violations should generate error if:
10910 - GTID_MODE=ON or ON_PERMISSIVE and GTID_NEXT='AUTOMATIC' (since the
10911 transaction is expected to commit using a GTID), or
10912 - GTID_NEXT='UUID:NUMBER' (since the transaction is expected to
10913 commit usinga GTID), or
10914 - ENFORCE_GTID_CONSISTENCY=ON.
10915 */
10916
2/2
✓ Branch 0 taken 5602 times.
✓ Branch 1 taken 1341 times.
6943 if ((gtid_next_type == AUTOMATIC_GTID &&
10917
4/4
✓ Branch 0 taken 5261 times.
✓ Branch 1 taken 341 times.
✓ Branch 2 taken 6312 times.
✓ Branch 3 taken 290 times.
6943 gtid_mode >= Gtid_mode::ON_PERMISSIVE) ||
10918
2/2
✓ Branch 0 taken 280 times.
✓ Branch 1 taken 6032 times.
6312 gtid_next_type == ASSIGNED_GTID ||
10919 gtid_consistency_mode == GTID_CONSISTENCY_MODE_ON) {
10920
1/2
✓ Branch 0 taken 911 times.
✗ Branch 1 not taken.
911 global_sid_lock->unlock();
10921
1/2
✓ Branch 0 taken 911 times.
✗ Branch 1 not taken.
911 my_error(error_code, MYF(0));
10922 911 return false;
10923 } else {
10924 /*
10925 If we are not generating an error, we must increase the counter
10926 of GTID-violating transactions. This will prevent a concurrent
10927 client from executing a SET GTID_MODE or SET
10928 ENFORCE_GTID_CONSISTENCY statement that would be incompatible
10929 with this transaction.
10930
10931 If the transaction had already been accounted as a gtid violating
10932 transaction, then don't increment the counters, just issue the
10933 warning below. This prevents calling
10934 begin_automatic_gtid_violating_transaction or
10935 begin_anonymous_gtid_violating_transaction multiple times for the
10936 same transaction, which would make the counter go out of sync.
10937 */
10938
2/2
✓ Branch 0 taken 4665 times.
✓ Branch 1 taken 1367 times.
6032 if (!thd->has_gtid_consistency_violation) {
10939
2/2
✓ Branch 0 taken 3878 times.
✓ Branch 1 taken 787 times.
4665 if (gtid_next_type == AUTOMATIC_GTID)
10940
1/2
✓ Branch 0 taken 3878 times.
✗ Branch 1 not taken.
3878 gtid_state->begin_automatic_gtid_violating_transaction();
10941 else {
10942
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 787 times.
787 assert(gtid_next_type == ANONYMOUS_GTID);
10943
1/2
✓ Branch 0 taken 787 times.
✗ Branch 1 not taken.
787 gtid_state->begin_anonymous_gtid_violating_transaction();
10944 }
10945
10946 /*
10947 If a transaction generates multiple GTID violation conditions,
10948 it must still only update the counters once. Hence we use
10949 this per-thread flag to keep track of whether the thread has a
10950 consistency or not. This function must only be called if the
10951 transaction does not already have a GTID violation.
10952 */
10953 4665 thd->has_gtid_consistency_violation = true;
10954 }
10955
10956
1/2
✓ Branch 0 taken 6032 times.
✗ Branch 1 not taken.
6032 global_sid_lock->unlock();
10957
10958 // Generate warning if ENFORCE_GTID_CONSISTENCY = WARN.
10959
2/2
✓ Branch 0 taken 288 times.
✓ Branch 1 taken 5744 times.
6032 if (gtid_consistency_mode == GTID_CONSISTENCY_MODE_WARN) {
10960 // Need to print to log so that replication admin knows when users
10961 // have adjusted their workloads.
10962
8/16
✓ Branch 0 taken 288 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 288 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 288 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 288 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 288 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 288 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 288 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 288 times.
✗ Branch 15 not taken.
288 LogErr(WARNING_LEVEL, log_error_code);
10963 // Need to print to client so that users can adjust their workload.
10964
2/4
✓ Branch 0 taken 288 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 288 times.
✗ Branch 3 not taken.
288 push_warning(thd, Sql_condition::SL_WARNING, error_code,
10965 ER_THD_NONCONST(thd, error_code));
10966 }
10967 6032 return true;
10968 }
10969 6943 }
10970
10971 29133658 bool THD::is_ddl_gtid_compatible() {
10972
1/2
✓ Branch 0 taken 29134417 times.
✗ Branch 1 not taken.
29133658 DBUG_TRACE;
10973
10974 29134417 bool is_binlog_open{mysql_bin_log.is_open()};
10975 29134225 bool is_binlog_enabled_for_session{(variables.option_bits & OPTION_BIN_LOG) !=
10976 0};
10977
4/8
✓ Branch 0 taken 29134347 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 29134481 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 191 times.
✓ Branch 5 taken 29134290 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
29134225 DBUG_PRINT("info", ("is_binlog_open:%d is_binlog_enabled_for_session:%d",
10978 is_binlog_open, is_binlog_enabled_for_session));
10979 // If we are not going to log, then no problem, we can execute any
10980 // statement.
10981
4/4
✓ Branch 0 taken 24031647 times.
✓ Branch 1 taken 5102476 times.
✓ Branch 2 taken 1103250 times.
✓ Branch 3 taken 22928397 times.
29134123 if (!is_binlog_open || !is_binlog_enabled_for_session) return true;
10982
10983 22928397 bool is_create_table{lex->sql_command == SQLCOM_CREATE_TABLE};
10984 22928397 bool is_create_temporary_table{false};
10985 22928397 bool is_create_table_select{false};
10986 22928397 bool is_create_table_atomic{false};
10987
2/2
✓ Branch 0 taken 127060 times.
✓ Branch 1 taken 22801337 times.
22928397 if (is_create_table) {
10988 // Check this conditionally, since create_info and/or query_block
10989 // may be uninitialized if sql_command!=SQLCOM_CREATE_TABLE.
10990 127060 is_create_temporary_table =
10991 127060 (lex->create_info->options & HA_LEX_CREATE_TMP_TABLE);
10992
2/2
✓ Branch 0 taken 117643 times.
✓ Branch 1 taken 9417 times.
127060 if (!is_create_temporary_table)
10993
1/2
✓ Branch 0 taken 117643 times.
✗ Branch 1 not taken.
117643 is_create_table_select = !lex->query_block->field_list_is_empty();
10994 127060 is_create_table_atomic =
10995
1/2
✓ Branch 0 taken 127060 times.
✗ Branch 1 not taken.
127060 get_default_handlerton(this, lex->create_info->db_type)->flags &
10996 HTON_SUPPORTS_ATOMIC_DDL;
10997 }
10998
10999 22928397 bool is_drop_table{lex->sql_command == SQLCOM_DROP_TABLE};
11000 22928397 bool is_drop_temporary_table{false};
11001
2/2
✓ Branch 0 taken 100015 times.
✓ Branch 1 taken 22828382 times.
22928397 if (is_drop_table) is_drop_temporary_table = lex->drop_temporary;
11002
11003 22928397 bool is_in_transaction{in_multi_stmt_transaction_mode()};
11004
11005 22928299 bool is_in_sub_statement{in_sub_stmt != 0};
11006
11007 22928299 bool is_binlog_format_statement{variables.binlog_format ==
11008 BINLOG_FORMAT_STMT};
11009
11010
5/8
✓ Branch 0 taken 22928665 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 22928536 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 189 times.
✓ Branch 5 taken 22928347 times.
✓ Branch 6 taken 189 times.
✗ Branch 7 not taken.
22928299 DBUG_PRINT("info", ("is_create_table:%d is_create_temporary_table:%d "
11011 "is_create_table_select:%d is_create_table_atomic:%d "
11012 "is_drop_table:%d is_drop_temporary_table:%d "
11013 "is_in_transaction:%d is_in_sub_statement:%d "
11014 "is_binlog_format_statement:%d",
11015 is_create_table, is_create_temporary_table,
11016 is_create_table_select, is_create_table_atomic,
11017 is_drop_table, is_drop_temporary_table, is_in_transaction,
11018 is_in_sub_statement, is_binlog_format_statement));
11019
11020
3/4
✓ Branch 0 taken 8365 times.
✓ Branch 1 taken 22920171 times.
✓ Branch 2 taken 8365 times.
✗ Branch 3 not taken.
22928536 if (is_create_table_select && !is_create_temporary_table &&
11021
2/2
✓ Branch 0 taken 2480 times.
✓ Branch 1 taken 5885 times.
8365 !is_create_table_atomic) {
11022 /*
11023 CREATE ... SELECT (without TEMPORARY) for engines not supporting
11024 atomic DDL is unsafe because if binlog_format=row it will be
11025 logged as a CREATE TABLE followed by row events, re-executed
11026 non-atomically as two transactions, and then written to the
11027 slave's binary log as two separate transactions with the same
11028 GTID.
11029 */
11030
1/2
✓ Branch 0 taken 2480 times.
✗ Branch 1 not taken.
2480 return handle_gtid_consistency_violation(
11031 this, ER_GTID_UNSAFE_CREATE_SELECT,
11032 2480 ER_RPL_GTID_UNSAFE_STMT_CREATE_SELECT);
11033 }
11034
11035
6/6
✓ Branch 0 taken 22916196 times.
✓ Branch 1 taken 9860 times.
✓ Branch 2 taken 5939 times.
✓ Branch 3 taken 22910257 times.
✓ Branch 4 taken 3818 times.
✓ Branch 5 taken 11981 times.
22926056 if ((is_create_temporary_table || is_drop_temporary_table) &&
11036
2/2
✓ Branch 0 taken 3332 times.
✓ Branch 1 taken 486 times.
3818 is_binlog_format_statement &&
11037
2/2
✓ Branch 0 taken 385 times.
✓ Branch 1 taken 2947 times.
3332 (is_in_transaction || is_in_sub_statement)) {
11038 /*
11039 When @@session.binlog_format=statement,
11040 [CREATE|DROP] TEMPORARY TABLE is unsafe to execute inside a
11041 transaction or Procedure, because the [CREATE|DROP] statement on
11042 the temporary table will be executed and written into binary log
11043 with a GTID even if the transaction or Procedure is rolled back.
11044 */
11045
1/2
✓ Branch 0 taken 486 times.
✗ Branch 1 not taken.
896 return handle_gtid_consistency_violation(
11046 this, ER_CLIENT_GTID_UNSAFE_CREATE_DROP_TEMP_TABLE_IN_TRX_IN_SBR,
11047 486 ER_SERVER_GTID_UNSAFE_CREATE_DROP_TEMP_TABLE_IN_TRX_IN_SBR);
11048 }
11049
11050 22925160 return true;
11051 29133852 }
11052
11053 31947024 bool THD::is_dml_gtid_compatible(bool some_transactional_table,
11054 bool some_non_transactional_table,
11055 bool non_transactional_tables_are_tmp) {
11056
1/2
✓ Branch 0 taken 31948587 times.
✗ Branch 1 not taken.
31947024 DBUG_TRACE;
11057
11058 // If @@session.sql_log_bin has been manually turned off (only
11059 // doable by SUPER), then no problem, we can execute any statement.
11060
2/4
✓ Branch 0 taken 31948601 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 31948520 times.
63897121 if ((variables.option_bits & OPTION_BIN_LOG) == 0 ||
11061
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 31948520 times.
31948601 mysql_bin_log.is_open() == false)
11062 return true;
11063
11064 /*
11065 Single non-transactional updates are allowed when not mixed
11066 together with transactional statements within a transaction.
11067 Furthermore, writing to transactional and non-transactional
11068 engines in a single statement is also disallowed.
11069 Multi-statement transactions on non-transactional tables are
11070 split into single-statement transactions when
11071 GTID_NEXT = "AUTOMATIC".
11072
11073 Non-transactional updates are allowed when row binlog format is
11074 used and all non-transactional tables are temporary.
11075
11076 The debug symbol "allow_gtid_unsafe_non_transactional_updates"
11077 disables the error. This is useful because it allows us to run
11078 old tests that were not written with the restrictions of GTIDs in
11079 mind.
11080 */
11081
6/10
✓ Branch 0 taken 31948548 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 31948638 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 148 times.
✓ Branch 5 taken 31948490 times.
✓ Branch 6 taken 148 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 148 times.
✗ Branch 9 not taken.
31948520 DBUG_PRINT("info", ("some_non_transactional_table=%d "
11082 "some_transactional_table=%d "
11083 "trans_has_updated_trans_table=%d "
11084 "non_transactional_tables_are_tmp=%d "
11085 "is_current_stmt_binlog_format_row=%d",
11086 some_non_transactional_table, some_transactional_table,
11087 trans_has_updated_trans_table(this),
11088 non_transactional_tables_are_tmp,
11089 is_current_stmt_binlog_format_row()));
11090
2/2
✓ Branch 0 taken 387813 times.
✓ Branch 1 taken 2117 times.
389930 if (some_non_transactional_table &&
11091
3/4
✓ Branch 0 taken 387877 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2177 times.
✓ Branch 3 taken 385700 times.
387813 (some_transactional_table || trans_has_updated_trans_table(this)) &&
11092
3/4
✓ Branch 0 taken 568 times.
✓ Branch 1 taken 3726 times.
✓ Branch 2 taken 870 times.
✗ Branch 3 not taken.
4862 !(non_transactional_tables_are_tmp &&
11093
4/4
✓ Branch 0 taken 389930 times.
✓ Branch 1 taken 31558708 times.
✓ Branch 2 taken 3977 times.
✓ Branch 3 taken 31944041 times.
32338516 is_current_stmt_binlog_format_row()) &&
11094
2/4
✓ Branch 0 taken 3977 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3977 times.
✗ Branch 3 not taken.
4661 !DBUG_EVALUATE_IF("allow_gtid_unsafe_non_transactional_updates", 1, 0)) {
11095
1/2
✓ Branch 0 taken 3977 times.
✗ Branch 1 not taken.
3977 return handle_gtid_consistency_violation(
11096 this, ER_GTID_UNSAFE_NON_TRANSACTIONAL_TABLE,
11097 3977 ER_RPL_GTID_UNSAFE_STMT_ON_NON_TRANS_TABLE);
11098 }
11099
11100 31944041 return true;
11101 31948018 }
11102
11103 /*
11104 Implementation of interface to write rows to the binary log through the
11105 thread. The thread is responsible for writing the rows it has
11106 inserted/updated/deleted.
11107 */
11108
11109 /*
11110 Template member function for ensuring that there is an rows log
11111 event of the appropriate type before proceeding.
11112
11113 PRE CONDITION:
11114 - Events of type 'RowEventT' have the type code 'type_code'.
11115
11116 POST CONDITION:
11117 If a non-NULL pointer is returned, the pending event for thread 'thd' will
11118 be an event of type 'RowEventT' (which have the type code 'type_code')
11119 will either empty or have enough space to hold 'needed' bytes. In
11120 addition, the columns bitmap will be correct for the row, meaning that
11121 the pending event will be flushed if the columns in the event differ from
11122 the columns suppled to the function.
11123
11124 RETURNS
11125 If no error, a non-NULL pending event (either one which already existed or
11126 the newly created one).
11127 If error, NULL.
11128 */
11129
11130 template <class RowsEventT>
11131 190874398 Rows_log_event *THD::binlog_prepare_pending_rows_event(
11132 TABLE *table, uint32 serv_id, size_t needed, bool is_transactional,
11133 const unsigned char *extra_row_info, uint32 source_part_id) {
11134
1/2
✓ Branch 0 taken 95448963 times.
✗ Branch 1 not taken.
190874398 DBUG_TRACE;
11135
11136
3/4
✓ Branch 0 taken 95440116 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 95440110 times.
190897926 DBUG_EXECUTE_IF("simulate_null_pending_rows_event", { return nullptr; });
11137
11138 /* Fetch the type code for the RowsEventT template parameter */
11139 190880220 int const general_type_code = RowsEventT::TYPE_CODE;
11140
11141 190880220 partition_info *part_info = table->part_info;
11142
1/2
✓ Branch 0 taken 95421613 times.
✗ Branch 1 not taken.
190880220 auto part_id = get_rpl_part_id(part_info);
11143
11144
1/2
✓ Branch 0 taken 95401010 times.
✗ Branch 1 not taken.
190843226 Rows_log_event *pending = binlog_get_pending_rows_event(is_transactional);
11145
11146
5/8
✓ Branch 0 taken 84973969 times.
✓ Branch 1 taken 10427041 times.
✓ Branch 2 taken 84984114 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 84984114 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 95412851 times.
190802020 if (unlikely(pending && !pending->is_valid())) return nullptr;
11147
11148 /*
11149 Check if the current event is non-NULL and a write-rows
11150 event. Also check if the table provided is mapped: if it is not,
11151 then we have switched to writing to a new table.
11152 If there is no pending event, we need to create one. If there is a pending
11153 event, but it's not about the same table id, or not of the same type
11154 (between Write, Update and Delete), or not the same affected columns, or
11155 going to be too big, flush this event to disk and create a new pending
11156 event.
11157
11158 We do not need to check that the pending event and the new event
11159 have the same setting for partial json updates, because
11160 partialness of json can only be changed outside transactions.
11161 */
11162
3/4
✓ Branch 0 taken 84986756 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 84963113 times.
✓ Branch 3 taken 32596 times.
339959226 if (!pending || pending->server_id != serv_id ||
11163 169973512 pending->get_table_id() != table->s->table_map_id ||
11164
2/4
✓ Branch 0 taken 84947638 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 84960735 times.
✗ Branch 3 not taken.
169926226 pending->get_general_type_code() != general_type_code ||
11165
3/4
✓ Branch 0 taken 84976594 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 84561992 times.
✓ Branch 3 taken 414602 times.
169921470 pending->get_data_size() + needed > binlog_row_event_max_size ||
11166
6/8
✓ Branch 0 taken 84983904 times.
✓ Branch 1 taken 10428947 times.
✓ Branch 2 taken 84552054 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 84556206 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 26053452 times.
✓ Branch 7 taken 69350625 times.
529908250 pending->read_write_bitmaps_cmp(table) == false ||
11167
3/4
✓ Branch 0 taken 84548033 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15197372 times.
✓ Branch 3 taken 69350661 times.
169112412 !(pending->m_extra_row_info.compare_extra_row_info(
11168 extra_row_info, part_id, source_part_id))) {
11169 /* Create a new RowsEventT... */
11170
1/2
✓ Branch 0 taken 26054021 times.
✗ Branch 1 not taken.
52106904 Rows_log_event *const ev = new RowsEventT(
11171
1/2
✓ Branch 0 taken 26053739 times.
✗ Branch 1 not taken.
52108042 this, table, table->s->table_map_id, is_transactional, extra_row_info);
11172
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26053779 times.
52107478 if (unlikely(!ev)) return nullptr;
11173 52107558 ev->server_id = serv_id; // I don't like this, it's too easy to forget.
11174 /*
11175 flush the pending event and replace it with the newly created
11176 event...
11177 */
11178
2/4
✓ Branch 0 taken 26053923 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 26053901 times.
52107558 if (unlikely(mysql_bin_log.flush_and_set_pending_rows_event(
11179 this, ev, is_transactional))) {
11180 delete ev;
11181 4 return nullptr;
11182 }
11183
11184 52107802 return ev; /* This is the new pending event */
11185 }
11186 138701250 return pending; /* This is the current pending event */
11187 190809068 }
11188
11189 /* Declare in unnamed namespace. */
11190 namespace {
11191
11192 /**
11193 Class to handle temporary allocation of memory for row data.
11194
11195 The responsibilities of the class is to provide memory for
11196 packing one or two rows of packed data (depending on what
11197 constructor is called).
11198
11199 In order to make the allocation more efficient for rows without blobs,
11200 a pointer to the allocated memory is stored in the table structure
11201 for such rows. If memory for a table containing a blob field
11202 is requested, only memory for that is allocated, and subsequently
11203 released when the object is destroyed.
11204
11205 */
11206 class Row_data_memory {
11207 public:
11208 /**
11209 Build an object to keep track of a block-local piece of memory
11210 for storing a row of data.
11211
11212 @param table
11213 Table where the pre-allocated memory is stored.
11214
11215 @param data
11216 Pointer to the table record.
11217 */
11218 92377214 Row_data_memory(TABLE *table, const uchar *data) : m_memory(nullptr) {
11219 #ifndef NDEBUG
11220 92377214 m_alloc_checked = false;
11221 #endif
11222 92377214 allocate_memory(table, max_row_length(table, data));
11223
1/2
✓ Branch 0 taken 92430388 times.
✗ Branch 1 not taken.
92433384 m_ptr[0] = has_memory() ? m_memory : nullptr;
11224 92430388 m_ptr[1] = nullptr;
11225 92430388 }
11226
11227 3018045 Row_data_memory(TABLE *table, const uchar *data1, const uchar *data2,
11228 ulonglong value_options = 0)
11229 3018045 : m_memory(nullptr) {
11230 #ifndef NDEBUG
11231 3018045 m_alloc_checked = false;
11232 #endif
11233 3018045 size_t len1 = max_row_length(table, data1);
11234 3018045 size_t len2 = max_row_length(table, data2, value_options);
11235 3018045 allocate_memory(table, len1 + len2);
11236
1/2
✓ Branch 0 taken 3018045 times.
✗ Branch 1 not taken.
3018045 m_ptr[0] = has_memory() ? m_memory : nullptr;
11237
1/2
✓ Branch 0 taken 3018045 times.
✗ Branch 1 not taken.
3018045 m_ptr[1] = has_memory() ? m_memory + len1 : nullptr;
11238 3018045 }
11239
11240 95435914 ~Row_data_memory() {
11241
3/4
✓ Branch 0 taken 95439839 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3816325 times.
✓ Branch 3 taken 91623514 times.
95435914 if (m_memory != nullptr && m_release_memory_on_destruction)
11242 3816325 my_free(m_memory);
11243 95435915 }
11244
11245 /**
11246 Is there memory allocated?
11247
11248 @retval true There is memory allocated
11249 @retval false Memory allocation failed
11250 */
11251 193864893 bool has_memory() const {
11252 #ifndef NDEBUG
11253 193864893 m_alloc_checked = true;
11254 #endif
11255 193864893 return m_memory != nullptr;
11256 }
11257
11258 98466648 uchar *slot(uint s) {
11259
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 98466648 times.
98466648 assert(s < sizeof(m_ptr) / sizeof(*m_ptr));
11260
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 98466648 times.
98466648 assert(m_ptr[s] != nullptr);
11261
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 98466648 times.
98466648 assert(m_alloc_checked == true);
11262 98466648 return m_ptr[s];
11263 }
11264
11265 private:
11266 /**
11267 Compute an upper bound on the amount of memory needed.
11268
11269 This may return an over-approximation.
11270
11271 @param table The table
11272 @param data The server's row record.
11273 @param value_options The value of @@global.binlog_row_value_options
11274 */
11275 98402942 size_t max_row_length(TABLE *table, const uchar *data,
11276 ulonglong value_options = 0) {
11277 98402942 TABLE_SHARE *table_s = table->s;
11278
1/2
✓ Branch 0 taken 98472910 times.
✗ Branch 1 not taken.
98402942 Replicated_columns_view fields{table, Replicated_columns_view::OUTBOUND};
11279 /*
11280 The server stores rows using "records". A record is a sequence of bytes
11281 which contains values or pointers to values for all fields (columns). The
11282 server uses table_s->reclength bytes for a row record.
11283
11284 The layout of a record is roughly:
11285
11286 - N+1+B bits, packed into CEIL((N+1+B)/8) bytes, where N is the number of
11287 nullable columns in the table, and B is the sum of the number of bits of
11288 all BIT columns.
11289
11290 - A sequence of serialized fields, each corresponding to a non-BIT,
11291 non-NULL column in the table.
11292
11293 For variable-length columns, the first component of the serialized field
11294 is a length, stored using 1, 2, 3, or 4 bytes depending on the maximum
11295 length for the data type.
11296
11297 For most data types, the next component of the serialized field is the
11298 actual data. But for for VARCHAR, VARBINARY, TEXT, BLOB, and JSON, the
11299 next component of the serialized field is a serialized pointer,
11300 i.e. sizeof(pointer) bytes, which point to another memory area where the
11301 actual data is stored.
11302
11303 The layout of a row image in the binary log is roughly:
11304
11305 - If this is an after-image and partial JSON is enabled, 1 byte containing
11306 value_options. If the PARTIAL_JSON bit of value_options is set, this is
11307 followed by P bits (the "partial_bits"), packed into CEIL(P) bytes,
11308 where P is the number of JSON columns in the table.
11309
11310 - M bits (the "null_bits"), packed into CEIL(M) bytes, where M is the
11311 number of columns in the image.
11312
11313 - A sequence of serialized fields, each corresponding to a non-NULL column
11314 in the row image.
11315
11316 For variable-length columns, the first component of the serialized field
11317 is a length, stored using 1, 2, 3, or 4 bytes depending on the maximum
11318 length for the data type.
11319
11320 For most data types, the next component of the serialized field is the
11321 actual field data. But for JSON fields where the corresponding bit of
11322 the partial_bits is 1, this is a sequence of diffs instead.
11323
11324 Now we try to use table_s->reclength to estimate how much memory to
11325 allocate for a row image in the binlog. Due to the differences this will
11326 only be an upper bound. Notice the differences:
11327
11328 - The binlog may only include a subset of the fields (the row image),
11329 whereas reclength contains space for all fields.
11330
11331 - BIT columns are not packed together with NULL bits in the binlog, so up
11332 to 1 more byte per BIT column may be needed.
11333
11334 - The binlog has a null bit even for non-nullable fields, whereas the
11335 reclength only contains space nullable fields, so the binlog may need up
11336 to CEIL(table_s->fields/8) more bytes.
11337
11338 - The binlog only has a null bit for fields in the image, whereas the
11339 reclength contains space for all fields.
11340
11341 - The binlog contains the full blob whereas the record only contains
11342 sizeof(pointer) bytes.
11343
11344 - The binlog contains value_options and partial_bits. So this may use up
11345 to 1+CEIL(table_s->fields/8) more bytes.
11346
11347 - The binlog may contain partial JSON. This is guaranteed to be smaller
11348 than the size of the full value.
11349
11350 - There may exist columns that, due to their nature, are not replicated,
11351 for instance, hidden generated columns used for functional indexes.
11352
11353 For those data types that are not stored using a pointer, the size of the
11354 field in the binary log is at most 2 bytes more than what the field
11355 contributes to in table_s->reclength, because those data types use at most
11356 1 byte for the length and waste less than a byte on extra padding and
11357 extra bits in null_bits or BIT columns.
11358
11359 For those data types that are stored using a pointer, the size of the
11360 field in the binary log is at most 2 bytes more than what the field
11361 contributes to in table_s->reclength, plus the size of the data. The size
11362 of the pointer is at least 4 on all supported platforms, so it is bigger
11363 than what is used by partial_bits, value_format, or any waste due to extra
11364 padding and extra bits in null_bits.
11365 */
11366 98472910 size_t length = table_s->reclength + 2 * (fields.filtered_size());
11367
11368
2/2
✓ Branch 0 taken 7121237 times.
✓ Branch 1 taken 98386799 times.
105508036 for (uint i = 0; i < table_s->blob_fields; i++) {
11369
2/2
✓ Branch 0 taken 1259 times.
✓ Branch 1 taken 7120038 times.
7121237 if (fields.is_excluded(table_s->blob_field[i])) continue;
11370
11371 7120038 Field *field = table->field[table_s->blob_field[i]];
11372 7120038 Field_blob *field_blob = down_cast<Field_blob *>(field);
11373
11374
5/6
✓ Branch 0 taken 7120037 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 322505 times.
✓ Branch 3 taken 6797532 times.
✓ Branch 4 taken 6738 times.
✓ Branch 5 taken 7113299 times.
7442539 if (field_blob->type() == MYSQL_TYPE_JSON &&
11375
2/2
✓ Branch 0 taken 6738 times.
✓ Branch 1 taken 315767 times.
322505 (value_options & PARTIAL_JSON_UPDATES) != 0) {
11376 6738 Field_json *field_json = down_cast<Field_json *>(field_blob);
11377
1/2
✓ Branch 0 taken 6738 times.
✗ Branch 1 not taken.
6738 length += field_json->get_diff_vector_and_length(value_options);
11378 } else
11379 7113298 length +=
11380
1/2
✓ Branch 0 taken 7113298 times.
✗ Branch 1 not taken.
7113299 field_blob->get_length(data + field_blob->offset(table->record[0]));
11381 }
11382 98469071 return length;
11383 98386799 }
11384
11385 95444125 void allocate_memory(TABLE *const table, const size_t total_length) {
11386
2/2
✓ Branch 0 taken 91633275 times.
✓ Branch 1 taken 3810850 times.
95444125 if (table->s->blob_fields == 0) {
11387 /*
11388 The maximum length of a packed record is less than this
11389 length. We use this value instead of the supplied length
11390 when allocating memory for records, since we don't know how
11391 the memory will be used in future allocations.
11392
11393 Since table->s->reclength is for unpacked records, we have
11394 to add two bytes for each field, which can potentially be
11395 added to hold the length of a packed field.
11396 */
11397 91633275 size_t const maxlen = table->s->reclength + 2 * table->s->fields;
11398
11399 /*
11400 Allocate memory for two records if memory hasn't been
11401 allocated. We allocate memory for two records so that it can
11402 be used when processing update rows as well.
11403 */
11404
2/2
✓ Branch 0 taken 84892 times.
✓ Branch 1 taken 91548383 times.
91633275 if (table->write_row_record == nullptr)
11405 84892 table->write_row_record = (uchar *)table->mem_root.Alloc(2 * maxlen);
11406 91633275 m_memory = table->write_row_record;
11407 91633275 m_release_memory_on_destruction = false;
11408 } else {
11409 3810850 m_memory = (uchar *)my_malloc(key_memory_Row_data_memory_memory,
11410 total_length, MYF(MY_WME));
11411 3816326 m_release_memory_on_destruction = true;
11412 }
11413 95449601 }
11414
11415 #ifndef NDEBUG
11416 mutable bool m_alloc_checked;
11417 #endif
11418 bool m_release_memory_on_destruction;
11419 uchar *m_memory;
11420 uchar *m_ptr[2];
11421 };
11422
11423 } // namespace
11424
11425 90373260 int THD::binlog_write_row(TABLE *table, bool is_trans, uchar const *record,
11426 const unsigned char *extra_row_info) {
11427
3/4
✓ Branch 0 taken 90415057 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 90415966 times.
✓ Branch 3 taken 4162 times.
90373260 assert(is_current_stmt_binlog_format_row() && mysql_bin_log.is_open());
11428
11429 /*
11430 Pack records into format for transfer. We are allocating more
11431 memory than needed, but that doesn't matter.
11432 */
11433
1/2
✓ Branch 0 taken 90446200 times.
✗ Branch 1 not taken.
90415966 Row_data_memory memory(table, record);
11434
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 90444310 times.
90446200 if (!memory.has_memory()) return HA_ERR_OUT_OF_MEM;
11435
11436 90444310 uchar *row_data = memory.slot(0);
11437
11438
1/2
✓ Branch 0 taken 90450147 times.
✗ Branch 1 not taken.
90447631 size_t const len = pack_row(table, table->write_set, row_data, record,
11439 enum_row_image_type::WRITE_AI);
11440
11441 Rows_log_event *const ev =
11442
1/2
✓ Branch 0 taken 90443893 times.
✗ Branch 1 not taken.
90450147 binlog_prepare_pending_rows_event<Write_rows_log_event>(
11443 table, server_id, len, is_trans, extra_row_info);
11444
11445
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 90444189 times.
90443893 if (unlikely(ev == nullptr)) return HA_ERR_OUT_OF_MEM;
11446
11447
1/2
✓ Branch 0 taken 90438129 times.
✗ Branch 1 not taken.
90444189 return ev->add_row_data(row_data, len);
11448 90438133 }
11449
11450 3018045 int THD::binlog_update_row(TABLE *table, bool is_trans,
11451 const uchar *before_record,
11452 const uchar *after_record,
11453 const unsigned char *extra_row_info) {
11454
2/4
✓ Branch 0 taken 3018045 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3018045 times.
✗ Branch 3 not taken.
3018045 assert(is_current_stmt_binlog_format_row() && mysql_bin_log.is_open());
11455 3018045 int error = 0;
11456
11457 /**
11458 Save a reference to the original read and write set bitmaps.
11459 We will need this to restore the bitmaps at the end.
11460 */
11461 3018045 MY_BITMAP *old_read_set = table->read_set;
11462 3018045 MY_BITMAP *old_write_set = table->write_set;
11463
11464 /**
11465 This will remove spurious fields required during execution but
11466 not needed for binlogging. This is done according to the:
11467 binlog-row-image option.
11468 */
11469
1/2
✓ Branch 0 taken 3018045 times.
✗ Branch 1 not taken.
3018045 binlog_prepare_row_images(this, table);
11470
11471 Row_data_memory row_data(table, before_record, after_record,
11472
1/2
✓ Branch 0 taken 3018045 times.
✗ Branch 1 not taken.
3018045 variables.binlog_row_value_options);
11473
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3018045 times.
3018045 if (!row_data.has_memory()) return HA_ERR_OUT_OF_MEM;
11474
11475 3018045 uchar *before_row = row_data.slot(0);
11476 3018045 uchar *after_row = row_data.slot(1);
11477
11478 size_t const before_size =
11479
1/2
✓ Branch 0 taken 3018045 times.
✗ Branch 1 not taken.
3018045 pack_row(table, table->read_set, before_row, before_record,
11480 enum_row_image_type::UPDATE_BI);
11481 6036090 size_t const after_size = pack_row(
11482
1/2
✓ Branch 0 taken 3018045 times.
✗ Branch 1 not taken.
3018045 table, table->write_set, after_row, after_record,
11483 enum_row_image_type::UPDATE_AI, variables.binlog_row_value_options);
11484
11485
1/2
✓ Branch 0 taken 3018045 times.
✗ Branch 1 not taken.
3018045 DBUG_DUMP("before_record", before_record, table->s->reclength);
11486
1/2
✓ Branch 0 taken 3018045 times.
✗ Branch 1 not taken.
3018045 DBUG_DUMP("after_record", after_record, table->s->reclength);
11487
1/2
✓ Branch 0 taken 3018045 times.
✗ Branch 1 not taken.
3018045 DBUG_DUMP("before_row", before_row, before_size);
11488
1/2
✓ Branch 0 taken 3018045 times.
✗ Branch 1 not taken.
3018045 DBUG_DUMP("after_row", after_row, after_size);
11489
11490 3018045 partition_info *part_info = table->part_info;
11491 3018045 uint32 source_part_id = binary_log::Rows_event::Extra_row_info::UNDEFINED;
11492
2/2
✓ Branch 0 taken 55279 times.
✓ Branch 1 taken 2962766 times.
3018045 if (part_info) {
11493 55279 uint32 new_part_id = binary_log::Rows_event::Extra_row_info::UNDEFINED;
11494 55279 longlong func_value = 0;
11495
1/2
✓ Branch 0 taken 55279 times.
✗ Branch 1 not taken.
55279 get_parts_for_update(before_record, after_record, table->record[0],
11496 part_info, &source_part_id, &new_part_id, &func_value);
11497 }
11498
11499 Rows_log_event *const ev =
11500
1/2
✓ Branch 0 taken 3018045 times.
✗ Branch 1 not taken.
3018045 binlog_prepare_pending_rows_event<Update_rows_log_event>(
11501 table, server_id, before_size + after_size, is_trans, extra_row_info,
11502 source_part_id);
11503
11504
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3018043 times.
3018045 if (unlikely(ev == nullptr)) return HA_ERR_OUT_OF_MEM;
11505
11506
2/2
✓ Branch 0 taken 55278 times.
✓ Branch 1 taken 2962765 times.
3018043 if (part_info) {
11507 55278 ev->m_extra_row_info.set_source_partition_id(source_part_id);
11508 }
11509
11510
2/4
✓ Branch 0 taken 3018042 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3018042 times.
✗ Branch 3 not taken.
6036086 error = ev->add_row_data(before_row, before_size) ||
11511
2/4
✓ Branch 0 taken 3018043 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3018043 times.
3018042 ev->add_row_data(after_row, after_size);
11512
11513 /* restore read/write set for the rest of execution */
11514 3018043 table->column_bitmaps_set_no_signal(old_read_set, old_write_set);
11515
11516 3018042 bitmap_clear_all(&table->tmp_set);
11517
11518 3018042 return error;
11519 3018044 }
11520
11521 1984449 int THD::binlog_delete_row(TABLE *table, bool is_trans, uchar const *record,
11522 const unsigned char *extra_row_info) {
11523
2/4
✓ Branch 0 taken 1984449 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1984449 times.
✗ Branch 3 not taken.
1984449 assert(is_current_stmt_binlog_format_row() && mysql_bin_log.is_open());
11524 1984449 int error = 0;
11525
11526 /**
11527 Save a reference to the original read and write set bitmaps.
11528 We will need this to restore the bitmaps at the end.
11529 */
11530 1984449 MY_BITMAP *old_read_set = table->read_set;
11531 1984449 MY_BITMAP *old_write_set = table->write_set;
11532
11533 /**
11534 This will remove spurious fields required during execution but
11535 not needed for binlogging. This is done according to the:
11536 binlog-row-image option.
11537 */
11538
1/2
✓ Branch 0 taken 1984449 times.
✗ Branch 1 not taken.
1984449 binlog_prepare_row_images(this, table);
11539
11540 /*
11541 Pack records into format for transfer. We are allocating more
11542 memory than needed, but that doesn't matter.
11543 */
11544
1/2
✓ Branch 0 taken 1984449 times.
✗ Branch 1 not taken.
1984449 Row_data_memory memory(table, record);
11545
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1984449 times.
1984449 if (unlikely(!memory.has_memory())) return HA_ERR_OUT_OF_MEM;
11546
11547 1984449 uchar *row_data = memory.slot(0);
11548
11549
1/2
✓ Branch 0 taken 1984449 times.
✗ Branch 1 not taken.
1984449 DBUG_DUMP("table->read_set", (uchar *)table->read_set->bitmap,
11550 (table->s->fields + 7) / 8);
11551
1/2
✓ Branch 0 taken 1984449 times.
✗ Branch 1 not taken.
1984449 size_t const len = pack_row(table, table->read_set, row_data, record,
11552 enum_row_image_type::DELETE_BI);
11553
11554 Rows_log_event *const ev =
11555
1/2
✓ Branch 0 taken 1984449 times.
✗ Branch 1 not taken.
1984449 binlog_prepare_pending_rows_event<Delete_rows_log_event>(
11556 table, server_id, len, is_trans, extra_row_info);
11557
11558
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1984447 times.
1984449 if (unlikely(ev == nullptr)) return HA_ERR_OUT_OF_MEM;
11559
11560
1/2
✓ Branch 0 taken 1984447 times.
✗ Branch 1 not taken.
1984447 error = ev->add_row_data(row_data, len);
11561
11562 /* restore read/write set for the rest of execution */
11563 1984447 table->column_bitmaps_set_no_signal(old_read_set, old_write_set);
11564
11565 1984447 bitmap_clear_all(&table->tmp_set);
11566 1984447 return error;
11567 1984449 }
11568
11569 5002494 void binlog_prepare_row_images(const THD *thd, TABLE *table) {
11570
1/2
✓ Branch 0 taken 5002494 times.
✗ Branch 1 not taken.
5002494 DBUG_TRACE;
11571 /**
11572 Remove from read_set spurious columns. The write_set has been
11573 handled before in table->mark_columns_needed_for_update.
11574 */
11575
11576
9/12
✓ Branch 0 taken 21139941 times.
✓ Branch 1 taken 17292 times.
✓ Branch 2 taken 21157233 times.
✓ Branch 3 taken 5002494 times.
✓ Branch 4 taken 5002494 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 5002494 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 4 times.
✓ Branch 9 taken 5002490 times.
✓ Branch 10 taken 4 times.
✗ Branch 11 not taken.
26159727 DBUG_PRINT_BITSET("debug", "table->read_set (before preparing): %s",
11577 table->read_set);
11578
11579 /**
11580 if there is a primary key in the table (ie, user declared PK or a
11581 non-null unique index) and we dont want to ship the entire image,
11582 and the handler involved supports this.
11583 */
11584 13757704 if (table->s->primary_key < MAX_KEY &&
11585
6/6
✓ Branch 0 taken 3752716 times.
✓ Branch 1 taken 1249778 times.
✓ Branch 2 taken 17094 times.
✓ Branch 3 taken 3735622 times.
✓ Branch 4 taken 17094 times.
✓ Branch 5 taken 4985400 times.
5019588 (thd->variables.binlog_row_image < BINLOG_ROW_IMAGE_FULL) &&
11586
2/4
✓ Branch 0 taken 17094 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17094 times.
✗ Branch 3 not taken.
17094 !ha_check_storage_engine_flag(table->s->db_type(),
11587 HTON_NO_BINLOG_ROW_OPT)) {
11588 /**
11589 Just to be sure that tmp_set is currently not in use as
11590 the read_set already.
11591 */
11592
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17094 times.
17094 assert(table->read_set != &table->tmp_set);
11593 // Verify it's not used
11594
2/4
✓ Branch 0 taken 17094 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 17094 times.
17094 assert(bitmap_is_clear_all(&table->tmp_set));
11595
11596
2/3
✓ Branch 0 taken 9332 times.
✓ Branch 1 taken 7762 times.
✗ Branch 2 not taken.
17094 switch (thd->variables.binlog_row_image) {
11597 9332 case BINLOG_ROW_IMAGE_MINIMAL:
11598 /* MINIMAL: Mark only PK */
11599
1/2
✓ Branch 0 taken 9332 times.
✗ Branch 1 not taken.
9332 table->mark_columns_used_by_index_no_reset(table->s->primary_key,
11600 &table->tmp_set);
11601 9332 break;
11602 7762 case BINLOG_ROW_IMAGE_NOBLOB:
11603 /**
11604 NOBLOB: Remove unnecessary BLOB fields from read_set
11605 (the ones that are not part of PK).
11606 */
11607
1/2
✓ Branch 0 taken 7762 times.
✗ Branch 1 not taken.
7762 bitmap_union(&table->tmp_set, table->read_set);
11608
2/2
✓ Branch 0 taken 25217 times.
✓ Branch 1 taken 7762 times.
32979 for (Field **ptr = table->field; *ptr; ptr++) {
11609 25217 Field *field = (*ptr);
11610
5/6
✓ Branch 0 taken 25217 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5851 times.
✓ Branch 3 taken 19366 times.
✓ Branch 4 taken 4277 times.
✓ Branch 5 taken 20940 times.
31068 if ((field->type() == MYSQL_TYPE_BLOB) &&
11611
2/2
✓ Branch 0 taken 4277 times.
✓ Branch 1 taken 1574 times.
5851 !field->is_flag_set(PRI_KEY_FLAG))
11612 4277 bitmap_clear_bit(&table->tmp_set, field->field_index());
11613 }
11614 7762 break;
11615 default:
11616 assert(0); // impossible.
11617 }
11618
11619 /* set the temporary read_set */
11620 17094 table->column_bitmaps_set_no_signal(&table->tmp_set, table->write_set);
11621 }
11622
11623
9/12
✓ Branch 0 taken 21131319 times.
✓ Branch 1 taken 25914 times.
✓ Branch 2 taken 21157233 times.
✓ Branch 3 taken 5002494 times.
✓ Branch 4 taken 5002494 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 5002494 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 4 times.
✓ Branch 9 taken 5002490 times.
✓ Branch 10 taken 4 times.
✗ Branch 11 not taken.
26159727 DBUG_PRINT_BITSET("debug", "table->read_set (after preparing): %s",
11624 table->read_set);
11625 5002494 }
11626
11627 94351607 int THD::binlog_flush_pending_rows_event(bool stmt_end, bool is_transactional) {
11628
1/2
✓ Branch 0 taken 94353646 times.
✗ Branch 1 not taken.
94351607 DBUG_TRACE;
11629 /*
11630 We shall flush the pending event even if we are not in row-based
11631 mode: it might be the case that we left row-based mode before
11632 flushing anything (e.g., if we have explicitly locked tables).
11633 */
11634
2/2
✓ Branch 0 taken 35378847 times.
✓ Branch 1 taken 58974639 times.
94353646 if (!mysql_bin_log.is_open()) return 0;
11635
11636 /*
11637 Mark the event as the last event of a statement if the stmt_end
11638 flag is set.
11639 */
11640 58974639 int error = 0;
11641 58974758 if (Rows_log_event *pending =
11642
3/4
✓ Branch 0 taken 58974758 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10413940 times.
✓ Branch 3 taken 48560818 times.
58974639 binlog_get_pending_rows_event(is_transactional)) {
11643
1/2
✓ Branch 0 taken 10413987 times.
✗ Branch 1 not taken.
10413940 if (stmt_end) {
11644 10413987 pending->set_flags(Rows_log_event::STMT_END_F);
11645 10413868 binlog_table_maps = 0;
11646 }
11647
11648
1/2
✓ Branch 0 taken 10414029 times.
✗ Branch 1 not taken.
10413821 error = mysql_bin_log.flush_and_set_pending_rows_event(this, nullptr,
11649 is_transactional);
11650 }
11651
11652 58974847 return error;
11653 94353694 }
11654
11655 #if !defined(NDEBUG)
11656 106 static const char *show_query_type(THD::enum_binlog_query_type qtype) {
11657
2/3
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 86 times.
✗ Branch 2 not taken.
106 switch (qtype) {
11658 20 case THD::ROW_QUERY_TYPE:
11659 20 return "ROW";
11660 86 case THD::STMT_QUERY_TYPE:
11661 86 return "STMT";
11662 case THD::QUERY_TYPE_COUNT:
11663 default:
11664 assert(0 <= qtype && qtype < THD::QUERY_TYPE_COUNT);
11665 }
11666 static char buf[64];
11667 sprintf(buf, "UNKNOWN#%d", qtype);
11668 return buf;
11669 }
11670 #endif
11671
11672 /**
11673 Auxiliary function to reset the limit unsafety warning suppression.
11674 */
11675 static void reset_binlog_unsafe_suppression() {
11676 DBUG_TRACE;
11677 unsafe_warning_suppression_is_activated = false;
11678 limit_unsafe_warning_count = 0;
11679 limit_unsafe_suppression_start_time = my_getsystime() / 10000000;
11680 }
11681
11682 /**
11683 Auxiliary function to print warning in the error log.
11684 */
11685 2492 static void print_unsafe_warning_to_log(int unsafe_type, char *buf,
11686 const char *query) {
11687
1/2
✓ Branch 0 taken 2492 times.
✗ Branch 1 not taken.
2492 DBUG_TRACE;
11688
1/2
✓ Branch 0 taken 2492 times.
✗ Branch 1 not taken.
2492 sprintf(buf, ER_DEFAULT(ER_BINLOG_UNSAFE_STATEMENT),
11689
1/2
✓ Branch 0 taken 2492 times.
✗ Branch 1 not taken.
2492 ER_DEFAULT_NONCONST(LEX::binlog_stmt_unsafe_errcode[unsafe_type]));
11690
8/16
✓ Branch 0 taken 2492 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2492 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2492 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2492 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2492 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2492 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 2492 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 2492 times.
✗ Branch 15 not taken.
2492 LogErr(WARNING_LEVEL, ER_BINLOG_UNSAFE_MESSAGE_AND_STATEMENT, buf, query);
11691 2492 }
11692
11693 /**
11694 Auxiliary function to check if the warning for limit unsafety should be
11695 thrown or suppressed. Details of the implementation can be found in the
11696 comments inline.
11697
11698 @param buf Buffer to hold the warning message text
11699 @param unsafe_type The type of unsafety.
11700 @param query The actual query statement.
11701
11702 TODO: Remove this function and implement a general service for all warnings
11703 that would prevent flooding the error log. => switch to log_throttle class?
11704 */
11705 282 static void do_unsafe_limit_checkout(char *buf, int unsafe_type,
11706 const char *query) {
11707 ulonglong now;
11708
1/2
✓ Branch 0 taken 282 times.
✗ Branch 1 not taken.
282 DBUG_TRACE;
11709
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 282 times.
282 assert(unsafe_type == LEX::BINLOG_STMT_UNSAFE_LIMIT);
11710 282 limit_unsafe_warning_count++;
11711 /*
11712 INITIALIZING:
11713 If this is the first time this function is called with log warning
11714 enabled, the monitoring the unsafe warnings should start.
11715 */
11716
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 273 times.
282 if (limit_unsafe_suppression_start_time == 0) {
11717 9 limit_unsafe_suppression_start_time = my_getsystime() / 10000000;
11718
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 print_unsafe_warning_to_log(unsafe_type, buf, query);
11719 } else {
11720
1/2
✓ Branch 0 taken 273 times.
✗ Branch 1 not taken.
273 if (!unsafe_warning_suppression_is_activated)
11721
1/2
✓ Branch 0 taken 273 times.
✗ Branch 1 not taken.
273 print_unsafe_warning_to_log(unsafe_type, buf, query);
11722
11723
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 269 times.
273 if (limit_unsafe_warning_count >=
11724 LIMIT_UNSAFE_WARNING_ACTIVATION_THRESHOLD_COUNT) {
11725 4 now = my_getsystime() / 10000000;
11726
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (!unsafe_warning_suppression_is_activated) {
11727 /*
11728 ACTIVATION:
11729 We got LIMIT_UNSAFE_WARNING_ACTIVATION_THRESHOLD_COUNT warnings in
11730 less than LIMIT_UNSAFE_WARNING_ACTIVATION_TIMEOUT we activate the
11731 suppression.
11732 */
11733
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if ((now - limit_unsafe_suppression_start_time) <=
11734 LIMIT_UNSAFE_WARNING_ACTIVATION_TIMEOUT) {
11735 unsafe_warning_suppression_is_activated = true;
11736 DBUG_PRINT("info", ("A warning flood has been detected and the "
11737 "limit unsafety warning suppression has been "
11738 "activated."));
11739 } else {
11740 /*
11741 there is no flooding till now, therefore we restart the monitoring
11742 */
11743 4 limit_unsafe_suppression_start_time = my_getsystime() / 10000000;
11744 4 limit_unsafe_warning_count = 0;
11745 }
11746 } else {
11747 /*
11748 Print the suppression note and the unsafe warning.
11749 */
11750 LogErr(INFORMATION_LEVEL, ER_BINLOG_WARNING_SUPPRESSED,
11751 limit_unsafe_warning_count,
11752 (int)(now - limit_unsafe_suppression_start_time));
11753 print_unsafe_warning_to_log(unsafe_type, buf, query);
11754 /*
11755 DEACTIVATION: We got LIMIT_UNSAFE_WARNING_ACTIVATION_THRESHOLD_COUNT
11756 warnings in more than LIMIT_UNSAFE_WARNING_ACTIVATION_TIMEOUT, the
11757 suppression should be deactivated.
11758 */
11759 if ((now - limit_unsafe_suppression_start_time) >
11760 LIMIT_UNSAFE_WARNING_ACTIVATION_TIMEOUT) {
11761 reset_binlog_unsafe_suppression();
11762 DBUG_PRINT("info", ("The limit unsafety warning supression has "
11763 "been deactivated"));
11764 }
11765 }
11766 4 limit_unsafe_warning_count = 0;
11767 }
11768 }
11769 282 }
11770
11771 /**
11772 Auxiliary method used by @c binlog_query() to raise warnings.
11773
11774 The type of warning and the type of unsafeness is stored in
11775 THD::binlog_unsafe_warning_flags.
11776 */
11777 5653614 void THD::issue_unsafe_warnings() {
11778 char buf[MYSQL_ERRMSG_SIZE * 2];
11779
1/2
✓ Branch 0 taken 5653636 times.
✗ Branch 1 not taken.
5653614 DBUG_TRACE;
11780 /*
11781 Ensure that binlog_unsafe_warning_flags is big enough to hold all
11782 bits. This is actually a constant expression.
11783 */
11784 assert(LEX::BINLOG_STMT_UNSAFE_COUNT <=
11785 sizeof(binlog_unsafe_warning_flags) * CHAR_BIT);
11786
11787 5653636 uint32 unsafe_type_flags = binlog_unsafe_warning_flags;
11788
11789
2/2
✓ Branch 0 taken 577 times.
✓ Branch 1 taken 5653059 times.
5653636 if ((unsafe_type_flags & (1U << LEX::BINLOG_STMT_UNSAFE_LIMIT)) != 0) {
11790
2/2
✓ Branch 0 taken 502 times.
✓ Branch 1 taken 75 times.
577 if ((lex->sql_command == SQLCOM_DELETE ||
11791
2/2
✓ Branch 0 taken 63 times.
✓ Branch 1 taken 439 times.
502 lex->sql_command == SQLCOM_UPDATE) &&
11792
1/2
✓ Branch 0 taken 138 times.
✗ Branch 1 not taken.
138 lex->query_block->select_limit) {
11793 276 ORDER *order = (ORDER *)((lex->query_block->order_list.elements)
11794
2/2
✓ Branch 0 taken 103 times.
✓ Branch 1 taken 35 times.
138 ? lex->query_block->order_list.first
11795 : nullptr);
11796 414 if ((lex->query_block->select_limit &&
11797
1/2
✓ Branch 0 taken 138 times.
✗ Branch 1 not taken.
138 lex->query_block->select_limit->fixed &&
11798
5/8
✓ Branch 0 taken 138 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 138 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 138 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 83 times.
✓ Branch 7 taken 55 times.
414 lex->query_block->select_limit->val_int() == 0) ||
11799
3/4
✓ Branch 0 taken 138 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 83 times.
✓ Branch 3 taken 55 times.
138 is_order_deterministic(lex->query_tables,
11800 138 lex->query_block->where_cond(), order)) {
11801 83 unsafe_type_flags &= ~(1U << LEX::BINLOG_STMT_UNSAFE_LIMIT);
11802 }
11803 }
11804
2/2
✓ Branch 0 taken 230 times.
✓ Branch 1 taken 347 times.
577 if ((lex->sql_command == SQLCOM_INSERT_SELECT ||
11805
2/2
✓ Branch 0 taken 61 times.
✓ Branch 1 taken 169 times.
230 lex->sql_command == SQLCOM_REPLACE_SELECT) &&
11806
2/2
✓ Branch 0 taken 211 times.
✓ Branch 1 taken 197 times.
408 order_deterministic) {
11807 211 unsafe_type_flags &= ~(1U << LEX::BINLOG_STMT_UNSAFE_LIMIT);
11808 }
11809 }
11810
11811 /*
11812 For each unsafe_type, check if the statement is unsafe in this way
11813 and issue a warning.
11814 */
11815
2/2
✓ Branch 0 taken 146983813 times.
✓ Branch 1 taken 5655607 times.
152639420 for (int unsafe_type = 0; unsafe_type < LEX::BINLOG_STMT_UNSAFE_COUNT;
11816 unsafe_type++) {
11817
2/2
✓ Branch 0 taken 13092 times.
✓ Branch 1 taken 146970721 times.
146983813 if ((unsafe_type_flags & (1 << unsafe_type)) != 0) {
11818
2/4
✓ Branch 0 taken 13092 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13092 times.
✗ Branch 3 not taken.
13092 push_warning_printf(
11819 this, Sql_condition::SL_NOTE, ER_BINLOG_UNSAFE_STATEMENT,
11820 ER_THD(this, ER_BINLOG_UNSAFE_STATEMENT),
11821
1/2
✓ Branch 0 taken 13092 times.
✗ Branch 1 not taken.
13092 ER_THD_NONCONST(this, LEX::binlog_stmt_unsafe_errcode[unsafe_type]));
11822
4/4
✓ Branch 0 taken 2493 times.
✓ Branch 1 taken 10599 times.
✓ Branch 2 taken 2492 times.
✓ Branch 3 taken 1 times.
13092 if (log_error_verbosity > 1 && opt_log_unsafe_statements) {
11823
2/2
✓ Branch 0 taken 282 times.
✓ Branch 1 taken 2210 times.
2492 if (unsafe_type == LEX::BINLOG_STMT_UNSAFE_LIMIT)
11824
2/4
✓ Branch 0 taken 282 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 282 times.
✗ Branch 3 not taken.
282 do_unsafe_limit_checkout(buf, unsafe_type, query().str);
11825 else // cases other than LIMIT unsafety
11826
2/4
✓ Branch 0 taken 2210 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4181 times.
✗ Branch 3 not taken.
2210 print_unsafe_warning_to_log(unsafe_type, buf, query().str);
11827 }
11828 }
11829 }
11830 5655607 }
11831
11832 /**
11833 Log the current query.
11834
11835 The query will be logged in either row format or statement format
11836 depending on the value of @c current_stmt_binlog_format_row field and
11837 the value of the @c qtype parameter.
11838
11839 This function must be called:
11840
11841 - After the all calls to ha_*_row() functions have been issued.
11842
11843 - After any writes to system tables. Rationale: if system tables
11844 were written after a call to this function, and the master crashes
11845 after the call to this function and before writing the system
11846 tables, then the master and slave get out of sync.
11847
11848 - Before tables are unlocked and closed.
11849
11850 @see decide_logging_format
11851
11852 @retval 0 Success
11853
11854 @retval nonzero If there is a failure when writing the query (e.g.,
11855 write failure), then the error code is returned.
11856 */
11857 11140186 int THD::binlog_query(THD::enum_binlog_query_type qtype, const char *query_arg,
11858 size_t query_len, bool is_trans, bool direct,
11859 bool suppress_use, int errcode) {
11860
1/2
✓ Branch 0 taken 11140812 times.
✗ Branch 1 not taken.
11140186 DBUG_TRACE;
11861
5/8
✓ Branch 0 taken 11140593 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11140739 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 106 times.
✓ Branch 5 taken 11140633 times.
✓ Branch 6 taken 153 times.
✗ Branch 7 not taken.
11140812 DBUG_PRINT("enter",
11862 ("qtype: %s query: '%s'", show_query_type(qtype), query_arg));
11863
2/4
✓ Branch 0 taken 11140786 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11140741 times.
✗ Branch 3 not taken.
11140786 assert(query_arg && mysql_bin_log.is_open());
11864
11865
2/2
✓ Branch 0 taken 7841 times.
✓ Branch 1 taken 11132815 times.
11140741 if (get_binlog_local_stmt_filter() == BINLOG_FILTER_SET) {
11866 /*
11867 The current statement is to be ignored, and not written to
11868 the binlog. Do not call issue_unsafe_warnings().
11869 */
11870 7841 return 0;
11871 }
11872
11873 /*
11874 If we are not in prelocked mode, mysql_unlock_tables() will be
11875 called after this binlog_query(), so we have to flush the pending
11876 rows event with the STMT_END_F set to unlock all tables at the
11877 slave side as well.
11878
11879 If we are in prelocked mode, the flushing will be done inside the
11880 top-most close_thread_tables().
11881 */
11882
2/2
✓ Branch 0 taken 11051185 times.
✓ Branch 1 taken 81630 times.
11132815 if (this->locked_tables_mode <= LTM_LOCK_TABLES)
11883
3/4
✓ Branch 0 taken 11051294 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 11051288 times.
11051185 if (int error = binlog_flush_pending_rows_event(true, is_trans))
11884 6 return error;
11885
11886 /*
11887 Warnings for unsafe statements logged in statement format are
11888 printed in three places instead of in decide_logging_format().
11889 This is because the warnings should be printed only if the statement
11890 is actually logged. When executing decide_logging_format(), we cannot
11891 know for sure if the statement will be logged:
11892
11893 1 - sp_head::execute_procedure which prints out warnings for calls to
11894 stored procedures.
11895
11896 2 - sp_head::execute_function which prints out warnings for calls
11897 involving functions.
11898
11899 3 - THD::binlog_query (here) which prints warning for top level
11900 statements not covered by the two cases above: i.e., if not inside a
11901 procedure and a function.
11902
11903 Besides, we should not try to print these warnings if it is not
11904 possible to write statements to the binary log as it happens when
11905 the execution is inside a function, or generally speaking, when
11906 the variables.option_bits & OPTION_BIN_LOG is false.
11907 */
11908
4/4
✓ Branch 0 taken 10933423 times.
✓ Branch 1 taken 199495 times.
✓ Branch 2 taken 5644447 times.
✓ Branch 3 taken 5288976 times.
11132918 if ((variables.option_bits & OPTION_BIN_LOG) && sp_runtime_ctx == nullptr &&
11909
1/2
✓ Branch 0 taken 5644539 times.
✗ Branch 1 not taken.
5644447 !binlog_evt_union.do_union) {
11910
1/2
✓ Branch 0 taken 5644529 times.
✗ Branch 1 not taken.
5644539 issue_unsafe_warnings();
11911 5644529 order_deterministic = true;
11912 }
11913
11914
2/3
✓ Branch 0 taken 10704655 times.
✓ Branch 1 taken 428253 times.
✗ Branch 2 not taken.
11132908 switch (qtype) {
11915 /*
11916 ROW_QUERY_TYPE means that the statement may be logged either in
11917 row format or in statement format. If
11918 current_stmt_binlog_format is row, it means that the
11919 statement has already been logged in row format and hence shall
11920 not be logged again.
11921 */
11922 10704655 case THD::ROW_QUERY_TYPE:
11923
5/8
✓ Branch 0 taken 10704588 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10704639 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 20 times.
✓ Branch 5 taken 10704619 times.
✓ Branch 6 taken 20 times.
✗ Branch 7 not taken.
10704655 DBUG_PRINT("debug", ("is_current_stmt_binlog_format_row: %d",
11924 is_current_stmt_binlog_format_row()));
11925
2/2
✓ Branch 0 taken 10351869 times.
✓ Branch 1 taken 352764 times.
10704639 if (is_current_stmt_binlog_format_row()) return 0;
11926 [[fallthrough]];
11927
11928 /*
11929 STMT_QUERY_TYPE means that the query must be logged in statement
11930 format; it cannot be logged in row format. This is typically
11931 used by DDL statements. It is an error to use this query type
11932 if current_stmt_binlog_format_row is row.
11933
11934 @todo Currently there are places that call this method with
11935 STMT_QUERY_TYPE and current_stmt_binlog_format is row. Fix those
11936 places and add assert to ensure correct behavior. /Sven
11937 */
11938 case THD::STMT_QUERY_TYPE:
11939 /*
11940 The MYSQL_BIN_LOG::write() function will set the STMT_END_F flag and
11941 flush the pending rows event if necessary.
11942 */
11943 {
11944 Query_log_event qinfo(this, query_arg, query_len, is_trans, direct,
11945
1/2
✓ Branch 0 taken 780897 times.
✗ Branch 1 not taken.
781017 suppress_use, errcode);
11946 /*
11947 Binlog table maps will be irrelevant after a Query_log_event
11948 (they are just removed on the slave side) so after the query
11949 log event is written to the binary log, we pretend that no
11950 table maps were written.
11951 */
11952
1/2
✓ Branch 0 taken 780936 times.
✗ Branch 1 not taken.
780897 int error = mysql_bin_log.write_event(&qinfo);
11953 780936 binlog_table_maps = 0;
11954 780936 return error;
11955 780936 }
11956 break;
11957
11958 case THD::QUERY_TYPE_COUNT:
11959 default:
11960 assert(0 <= qtype && qtype < QUERY_TYPE_COUNT);
11961 }
11962 return 0;
11963 11140753 }
11964
11965 217128 static const binlog_cache_mngr *get_cache_mngr(THD *thd) {
11966 const binlog_cache_mngr *cache_mngr =
11967
2/2
✓ Branch 0 taken 213408 times.
✓ Branch 1 taken 3720 times.
217128 (thd && opt_bin_log)
11968
1/2
✓ Branch 0 taken 217128 times.
✗ Branch 1 not taken.
434256 ? static_cast<binlog_cache_mngr *>(thd_get_ha_data(thd, binlog_hton))
11969 217128 : nullptr;
11970
11971 217128 return cache_mngr;
11972 }
11973
11974 108564 static int show_binlog_vars(THD *thd, SHOW_VAR *var,
11975 char *buff [[maybe_unused]]) {
11976 108564 mysql_mutex_assert_owner(&LOCK_status);
11977
11978 108564 const binlog_cache_mngr *cache_mngr = get_cache_mngr(thd);
11979
11980
6/6
✓ Branch 0 taken 26021 times.
✓ Branch 1 taken 82543 times.
✓ Branch 2 taken 73 times.
✓ Branch 3 taken 25948 times.
✓ Branch 4 taken 73 times.
✓ Branch 5 taken 108491 times.
108564 if (cache_mngr && cache_mngr->has_consistent_snapshot()) {
11981 73 set_binlog_snapshot_file(cache_mngr->binlog_info.log_file_name);
11982 73 binlog_snapshot_position = cache_mngr->binlog_info.pos;
11983
2/2
✓ Branch 0 taken 106631 times.
✓ Branch 1 taken 1860 times.
108491 } else if (mysql_bin_log.is_open()) {
11984 106631 set_binlog_snapshot_file(binlog_global_snapshot_file);
11985 106631 binlog_snapshot_position = binlog_global_snapshot_position;
11986 } else {
11987 1860 binlog_snapshot_file[0] = '\0';
11988 1860 binlog_snapshot_position = 0;
11989 }
11990 108564 var->type = SHOW_ARRAY;
11991 108564 var->value = reinterpret_cast<char *>(&binlog_status_vars_detail);
11992 108564 return 0;
11993 }
11994
11995 108564 static int show_binlog_snapshot_gtid_executed(
11996 THD *thd, SHOW_VAR *var, char *buff [[maybe_unused]]) {
11997 108564 mysql_mutex_assert_owner(&LOCK_status);
11998
11999 108564 const binlog_cache_mngr *cache_mngr = get_cache_mngr(thd);
12000
12001
6/6
✓ Branch 0 taken 26021 times.
✓ Branch 1 taken 82543 times.
✓ Branch 2 taken 73 times.
✓ Branch 3 taken 25948 times.
✓ Branch 4 taken 73 times.
✓ Branch 5 taken 108491 times.
108564 if (cache_mngr && cache_mngr->has_consistent_snapshot()) {
12002 73 binlog_snapshot_gtid_executed = cache_mngr->snapshot_gtid_executed;
12003
2/2
✓ Branch 0 taken 106631 times.
✓ Branch 1 taken 1860 times.
108491 } else if (mysql_bin_log.is_open()) {
12004 106631 binlog_snapshot_gtid_executed = "not-in-consistent-snapshot";
12005 } else {
12006 1860 binlog_snapshot_gtid_executed.clear();
12007 }
12008
12009 108564 var->type = SHOW_CHAR;
12010 108564 var->value = const_cast<char *>(binlog_snapshot_gtid_executed.c_str());
12011 108564 return 0;
12012 }
12013
12014 static SHOW_VAR binlog_status_vars_top[] = {
12015 {"Binlog", (char *)&show_binlog_vars, SHOW_FUNC, SHOW_SCOPE_GLOBAL},
12016 {"Binlog_snapshot_gtid_executed",
12017 (char *)&show_binlog_snapshot_gtid_executed, SHOW_FUNC, SHOW_SCOPE_GLOBAL},
12018 {NullS, NullS, SHOW_LONG, SHOW_SCOPE_GLOBAL}};
12019
12020 namespace {
12021 11851827 void finish_transaction_in_engines(THD *thd, bool all, bool run_after_commit) {
12022
2/2
✓ Branch 0 taken 5924859 times.
✓ Branch 1 taken 5927007 times.
11851827 if (thd->get_transaction()->m_flags.commit_low) {
12023
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5924858 times.
5924859 if (trx_coordinator::commit_in_engines(thd, all, run_after_commit))
12024 thd->commit_error = THD::CE_COMMIT_ERROR;
12025
2/2
✓ Branch 0 taken 287 times.
✓ Branch 1 taken 5926751 times.
5927007 } else if (is_xa_rollback(thd)) {
12026
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 287 times.
287 if (trx_coordinator::rollback_in_engines(thd, all))
12027 thd->commit_error = THD::CE_COMMIT_ERROR;
12028 }
12029 11851896 }
12030 } // namespace
12031
12032 struct st_mysql_storage_engine binlog_storage_engine = {
12033 MYSQL_HANDLERTON_INTERFACE_VERSION};
12034
12035 /** @} */
12036
12037 mysql_declare_plugin(binlog){
12038 MYSQL_STORAGE_ENGINE_PLUGIN,
12039 &binlog_storage_engine,
12040 "binlog",
12041 PLUGIN_AUTHOR_ORACLE,
12042 "This is a pseudo storage engine to represent the binlog in a transaction",
12043 PLUGIN_LICENSE_GPL,
12044 binlog_init, /* Plugin Init */
12045 nullptr, /* Plugin Check uninstall */
12046 binlog_deinit, /* Plugin Deinit */
12047 0x0100 /* 1.0 */,
12048 binlog_status_vars_top, /* status variables */
12049 nullptr, /* system variables */
12050 nullptr, /* config options */
12051 0,
12052 } mysql_declare_plugin_end;
12053